动态构造任意复杂的 Linq Where 表达式
前言
Linq 是 C# 中一个非常好用的集合处理库,用好了能帮我们简化大量又臭又长的嵌套循环,使处理逻辑清晰可见。EF 查询主要也是依赖 Linq。但是 Linq 相对 sql 也存在一些缺点,最主要的就是动态构造查询的难度。sql 只需要简单进行字符串拼接,操作难度很低(当然出错也相当容易),而 Linq 表达式由于对强类型表达式树的依赖,动态构造查询表达式基本相当于手写 AST(抽象语法树),可以说难度暴增。
AST 已经进入编译原理的领域,对计算机系统的了解程度需求比一般 crud 写业务代码高了几个量级,也导致很多人觉得 EF 不好用,为了写个动态查询要学编译原理这个代价还是挺高的。后来也有一些类似 DynamicLinq 的类库能用表达式字符串写动态查询。
本着学习精神,研究了一段时间,写了一个在我的想象力范围内,可以动态构造任意复杂的 Where 表达式的辅助类。这个辅助类的过滤条件使用了 JqGrid 的高级查询的数据结构,这是我第一个知道能生成复杂嵌套查询,并且查询数据使用 json 方便解析的 js 表格插件。可以无缝根据 JqGrid 的高级查询生成 Where 表达式。
正文
实现
JqGrid 高级查询数据结构定义,用来反序列化:
public class JqGridParameter
{
/// <summary>
/// 是否搜索,本来应该是bool,true
/// </summary>
public string _search { get; set; }
/// <summary>
/// 请求发送次数,方便服务器处理重复请求
/// </summary>
public long Nd { get; set; }
/// <summary>
/// 当页数据条数
/// </summary>
public int Rows { get; set; }
/// <summary>
/// 页码
/// </summary>
public int Page { get; set; }
/// <summary>
/// 排序列,多列排序时为排序列名+空格+排序方式,多个列之间用逗号隔开。例:id asc,name desc
/// </summary>
public string Sidx { get; set; }
/// <summary>
/// 分离后的排序列
/// </summary>
public string[][] SIdx => Sidx.Split(", ").Select(s => s.Split(" ")).ToArray();
/// <summary>
/// 排序方式:asc、desc
/// </summary>
public string Sord { get; set; }
/// <summary>
/// 高级搜索条件json
/// </summary>
public string Filters { get; set; } /// <summary>
/// 序列化的高级搜索对象
/// </summary>
public JqGridSearchRuleGroup FilterObject => Filters.IsNullOrWhiteSpace()
? new JqGridSearchRuleGroup { Rules = new[] { new JqGridSearchRule { Op = SearchOper, Data = SearchString, Field = SearchField } } }
: JsonSerializer.Deserialize<JqGridSearchRuleGroup>(Filters ?? string.Empty); /// <summary>
/// 简单搜索字段
/// </summary>
public string SearchField { get; set; }
/// <summary>
/// 简单搜索关键字
/// </summary>
public string SearchString { get; set; }
/// <summary>
/// 简单搜索操作
/// </summary>
public string SearchOper { get; set; } } /// <summary>
/// 高级搜索条件组
/// </summary>
public class JqGridSearchRuleGroup
{
/// <summary>
/// 条件组合方式:and、or
/// </summary>
public string GroupOp { get; set; }
/// <summary>
/// 搜索条件集合
/// </summary>
public JqGridSearchRule[] Rules { get; set; }
/// <summary>
/// 搜索条件组集合
/// </summary>
public JqGridSearchRuleGroup[] Groups { get; set; }
} /// <summary>
/// 高级搜索条件
/// </summary>
public class JqGridSearchRule
{
/// <summary>
/// 搜索字段
/// </summary>
public string Field { get; set; }
/// <summary>
/// 搜索字段的大驼峰命名
/// </summary>
public string PascalField => Field?.Length > ? Field.Substring(, ).ToUpper() + Field.Substring() : Field;
/// <summary>
/// 搜索操作
/// </summary>
public string Op { get; set; }
/// <summary>
/// 搜索关键字
/// </summary>
public string Data { get; set; }
}
Where 条件生成器,代码有点多,有点复杂。不过注释也很多,稍微耐心点应该不难看懂:
/// <summary>
/// JqGrid搜索表达式扩展
/// </summary>
public static class JqGridSearchExtensions
{
//前端的(不)属于条件搜索需要传递一个json数组的字符串作为参数
//为了避免在搜索字符串的时候分隔符是搜索内容的一部分导致搜索关键字出错
//无论定义什么分隔符都不能完全避免这种尴尬的情况,所以使用标准的json以绝后患
/// <summary>
/// 根据搜索条件构造where表达式,支持JqGrid高级搜索
/// </summary>
/// <typeparam name="T">搜索的对象类型</typeparam>
/// <param name="ruleGroup">JqGrid搜索条件组</param>
/// <param name="propertyMap">属性映射,把搜索规则的名称映射到属性名称,如果属性是复杂类型,使用点号可以继续访问内部属性</param>
/// <returns>where表达式</returns>
public static Expression<Func<T, bool>> BuildWhere<T>(JqGridSearchRuleGroup ruleGroup, IDictionary<string, string> propertyMap)
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "searchObject"); return Expression.Lambda<Func<T, bool>>(BuildGroupExpression<T>(ruleGroup, parameter, propertyMap), parameter);
} /// <summary>
/// 构造搜索条件组的表达式(一个组中可能包含若干子条件组)
/// </summary>
/// <typeparam name="T">搜索的对象类型</typeparam>
/// <param name="group">条件组</param>
/// <param name="parameter">参数表达式</param>
/// <param name="propertyMap">属性映射</param>
/// <returns>返回bool的条件组的表达式</returns>
private static Expression BuildGroupExpression<T>(JqGridSearchRuleGroup group, ParameterExpression parameter, IDictionary<string, string> propertyMap)
{
List<Expression> expressions = new List<Expression>();
foreach (var rule in group.Rules ?? new JqGridSearchRule[])
{
expressions.Add(BuildRuleExpression<T>(rule, parameter, propertyMap));
} foreach (var subGroup in group.Groups ?? new JqGridSearchRuleGroup[])
{
expressions.Add(BuildGroupExpression<T>(subGroup, parameter, propertyMap));
} if (expressions.Count == )
{
throw new InvalidOperationException("构造where子句异常,生成了0个比较条件表达式。");
} if (expressions.Count == )
{
return expressions[];
} var expression = expressions[];
switch (group.GroupOp)
{
case "AND":
foreach (var exp in expressions.Skip())
{
expression = Expression.AndAlso(expression, exp);
}
break;
case "OR":
foreach (var exp in expressions.Skip())
{
expression = Expression.OrElse(expression, exp);
}
break;
default:
throw new InvalidOperationException($"不支持创建{group.GroupOp}类型的逻辑运算表达式");
} return expression;
} private static readonly string[] SpecialRuleOps = {"in", "ni", "nu", "nn"}; /// <summary>
/// 构造条件表达式
/// </summary>
/// <typeparam name="T">搜索的对象类型</typeparam>
/// <param name="rule">条件</param>
/// <param name="parameter">参数</param>
/// <param name="propertyMap">属性映射</param>
/// <returns>返回bool的条件表达式</returns>
private static Expression BuildRuleExpression<T>(JqGridSearchRule rule, ParameterExpression parameter,
IDictionary<string, string> propertyMap)
{
Expression l; string[] names = null;
//如果实体属性名称和前端名称不一致,或者属性是一个自定义类型,需要继续访问其内部属性,使用点号分隔
if (propertyMap?.ContainsKey(rule.Field) == true)
{
names = propertyMap[rule.Field].Split('.', StringSplitOptions.RemoveEmptyEntries);
l = Expression.Property(parameter, names[]);
foreach (var name in names.Skip())
{
l = Expression.Property(l, name);
}
}
else
{
l = Expression.Property(parameter, rule.PascalField);
} Expression r = null; //值表达式
Expression e; //返回bool的各种比较表达式 //属于和不属于比较是多值比较,需要调用Contains方法,而不是调用比较操作符
//为空和不为空的右值为常量null,不需要构造
var specialRuleOps = SpecialRuleOps; var isNullable = false;
var pt = typeof(T);
if(names != null)
{
foreach(var name in names)
{
pt = pt.GetProperty(name).PropertyType;
}
}
else
{
pt = pt.GetProperty(rule.PascalField).PropertyType;
} //如果属性类型是可空值类型,取出内部类型
if (pt.IsDerivedFrom(typeof(Nullable<>)))
{
isNullable = true;
pt = pt.GenericTypeArguments[];
} //根据属性类型创建要比较的常量值表达式(也就是r)
if (!specialRuleOps.Contains(rule.Op))
{
switch (pt)
{
case Type ct when ct == typeof(bool):
r = BuildConstantExpression(rule, bool.Parse);
break; #region 文字 case Type ct when ct == typeof(char):
r = BuildConstantExpression(rule, str => str[]);
break;
case Type ct when ct == typeof(string):
r = BuildConstantExpression(rule, str => str);
break; #endregion #region 有符号整数 case Type ct when ct == typeof(sbyte):
r = BuildConstantExpression(rule, sbyte.Parse);
break;
case Type ct when ct == typeof(short):
r = BuildConstantExpression(rule, short.Parse);
break;
case Type ct when ct == typeof(int):
r = BuildConstantExpression(rule, int.Parse);
break;
case Type ct when ct == typeof(long):
r = BuildConstantExpression(rule, long.Parse);
break; #endregion #region 无符号整数 case Type ct when ct == typeof(byte):
r = BuildConstantExpression(rule, byte.Parse);
break;
case Type ct when ct == typeof(ushort):
r = BuildConstantExpression(rule, ushort.Parse);
break;
case Type ct when ct == typeof(uint):
r = BuildConstantExpression(rule, uint.Parse);
break;
case Type ct when ct == typeof(ulong):
r = BuildConstantExpression(rule, ulong.Parse);
break; #endregion #region 小数 case Type ct when ct == typeof(float):
r = BuildConstantExpression(rule, float.Parse);
break;
case Type ct when ct == typeof(double):
r = BuildConstantExpression(rule, double.Parse);
break;
case Type ct when ct == typeof(decimal):
r = BuildConstantExpression(rule, decimal.Parse);
break; #endregion #region 其它常用类型 case Type ct when ct == typeof(DateTime):
r = BuildConstantExpression(rule, DateTime.Parse);
break;
case Type ct when ct == typeof(DateTimeOffset):
r = BuildConstantExpression(rule, DateTimeOffset.Parse);
break;
case Type ct when ct == typeof(Guid):
r = BuildConstantExpression(rule, Guid.Parse);
break;
case Type ct when ct.IsEnum:
r = Expression.Constant(rule.Data.ToEnumObject(ct));
break; #endregion default:
throw new InvalidOperationException($"不支持创建{pt.FullName}类型的数据表达式");
}
} if (r != null && pt.IsValueType && isNullable)
{
var gt = typeof(Nullable<>).MakeGenericType(pt);
r = Expression.Convert(r, gt);
} switch (rule.Op)
{
case "eq": //等于
e = Expression.Equal(l, r);
break;
case "ne": //不等于
e = Expression.NotEqual(l, r);
break;
case "lt": //小于
e = Expression.LessThan(l, r);
break;
case "le": //小于等于
e = Expression.LessThanOrEqual(l, r);
break;
case "gt": //大于
e = Expression.GreaterThan(l, r);
break;
case "ge": //大于等于
e = Expression.GreaterThanOrEqual(l, r);
break;
case "bw": //开头是(字符串)
if (pt == typeof(string))
{
e = Expression.Call(l, pt.GetMethod(nameof(string.StartsWith), new[] {typeof(string)}), r);
}
else
{
throw new InvalidOperationException($"不支持创建{pt.FullName}类型的开始于表达式");
} break;
case "bn": //开头不是(字符串)
if (pt == typeof(string))
{
e = Expression.Not(Expression.Call(l, pt.GetMethod(nameof(string.StartsWith), new[] {typeof(string)}), r));
}
else
{
throw new InvalidOperationException($"不支持创建{pt.FullName}类型的不开始于表达式");
} break;
case "ew": //结尾是(字符串)
if (pt == typeof(string))
{
e = Expression.Call(l, pt.GetMethod(nameof(string.EndsWith), new[] {typeof(string)}), r);
}
else
{
throw new InvalidOperationException($"不支持创建{pt.FullName}类型的结束于表达式");
} break;
case "en": //结尾不是(字符串)
if (pt == typeof(string))
{
e = Expression.Not(Expression.Call(l, pt.GetMethod(nameof(string.EndsWith), new[] {typeof(string)}), r));
}
else
{
throw new InvalidOperationException($"不支持创建{pt.FullName}类型的不结束于表达式");
} break;
case "cn": //包含(字符串)
if (pt == typeof(string))
{
e = Expression.Call(l, pt.GetMethod(nameof(string.Contains), new[] {typeof(string)}), r);
}
else
{
throw new InvalidOperationException($"不支持创建{pt.FullName}类型的包含表达式");
} break;
case "nc": //不包含(字符串)
if (pt == typeof(string))
{
e = Expression.Not(Expression.Call(l, pt.GetMethod(nameof(string.Contains), new[] {typeof(string)}), r));
}
else
{
throw new InvalidOperationException($"不支持创建{pt.FullName}类型的包含表达式");
} break;
case "in": //属于(是候选值列表之一)
e = BuildContainsExpression(rule, l, pt);
break;
case "ni": //不属于(不是候选值列表之一)
e = Expression.Not(BuildContainsExpression(rule, l, pt));
break;
case "nu": //为空
r = Expression.Constant(null);
e = Expression.Equal(l, r);
break;
case "nn": //不为空
r = Expression.Constant(null);
e = Expression.Not(Expression.Equal(l, r));
break;
case "bt": //区间
throw new NotImplementedException($"尚未实现创建{rule.Op}类型的比较表达式");
default:
throw new InvalidOperationException($"不支持创建{rule.Op}类型的比较表达式");
} return e; static Expression BuildConstantExpression<TValue>(JqGridSearchRule jRule, Func<string, TValue> valueConvertor)
{
var rv = valueConvertor(jRule.Data);
return Expression.Constant(rv);
}
} /// <summary>
/// 构造Contains调用表达式
/// </summary>
/// <param name="rule">条件</param>
/// <param name="parameter">参数</param>
/// <param name="parameterType">参数类型</param>
/// <returns>Contains调用表达式</returns>
private static Expression BuildContainsExpression(JqGridSearchRule rule, Expression parameter, Type parameterType)
{
Expression e = null; var genMethod = typeof(Queryable).GetMethods()
.Single(m => m.Name == nameof(Queryable.Contains) && m.GetParameters().Length == ); var jsonArray = JsonSerializer.Deserialize<string[]>(rule.Data); switch (parameterType)
{
#region 文字 case Type ct when ct == typeof(char):
if (jsonArray.Any(o => o.Length != )) {throw new InvalidOperationException("字符型的候选列表中存在错误的候选项");}
e = CallContains(parameter, jsonArray, str => str[], genMethod, ct);
break;
case Type ct when ct == typeof(string):
e = CallContains(parameter, jsonArray, str => str, genMethod, ct);
break; #endregion #region 有符号整数 case Type ct when ct == typeof(sbyte):
e = CallContains(parameter, jsonArray, sbyte.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(short):
e = CallContains(parameter, jsonArray, short.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(int):
e = CallContains(parameter, jsonArray, int.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(long):
e = CallContains(parameter, jsonArray, long.Parse, genMethod, ct);
break; #endregion #region 无符号整数 case Type ct when ct == typeof(byte):
e = CallContains(parameter, jsonArray, byte.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(ushort):
e = CallContains(parameter, jsonArray, ushort.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(uint):
e = CallContains(parameter, jsonArray, uint.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(ulong):
e = CallContains(parameter, jsonArray, ulong.Parse, genMethod, ct);
break; #endregion #region 小数 case Type ct when ct == typeof(float):
e = CallContains(parameter, jsonArray, float.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(double):
e = CallContains(parameter, jsonArray, double.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(decimal):
e = CallContains(parameter, jsonArray, decimal.Parse, genMethod, ct);
break; #endregion #region 其它常用类型 case Type ct when ct == typeof(DateTime):
e = CallContains(parameter, jsonArray, DateTime.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(DateTimeOffset):
e = CallContains(parameter, jsonArray, DateTimeOffset.Parse, genMethod, ct);
break;
case Type ct when ct == typeof(Guid):
e = CallContains(parameter, jsonArray, Guid.Parse, genMethod, ct);
break;
case Type ct when ct.IsEnum:
e = CallContains(Expression.Convert(parameter, typeof(object)), jsonArray, enumString => enumString.ToEnumObject(ct), genMethod, ct);
break; #endregion
} return e; static MethodCallExpression CallContains<T>(Expression pa, string[] jArray, Func<string, T> selector, MethodInfo genericMethod, Type type)
{
var data = jArray.Select(selector).ToArray().AsQueryable();
var method = genericMethod.MakeGenericMethod(type); return Expression.Call(null, method, new[] { Expression.Constant(data), pa });
}
}
}
使用
此处是在 Razor Page 中使用,内部使用的其他辅助类和前端页面代码就不贴了,有兴趣的可以在我的文章末尾找到 GitHub 项目链接:
public async Task<IActionResult> OnGetUserListAsync([FromQuery]JqGridParameter jqGridParameter)
{
var usersQuery = _userManager.Users.AsNoTracking();
if (jqGridParameter._search == "true")
{
usersQuery = usersQuery.Where(BuildWhere<ApplicationUser>(jqGridParameter.FilterObject, null));
} var users = usersQuery.Include(u => u.UserRoles).ThenInclude(ur => ur.Role).OrderBy(u => u.InsertOrder)
.Skip((jqGridParameter.Page - ) * jqGridParameter.Rows).Take(jqGridParameter.Rows).ToList();
var userCount = usersQuery.Count();
var pageCount = Ceiling((double) userCount / jqGridParameter.Rows);
return new JsonResult(
new
{
rows //数据集合
= users.Select(u => new
{
u.UserName,
u.Gender,
u.Email,
u.PhoneNumber,
u.EmailConfirmed,
u.PhoneNumberConfirmed,
u.CreationTime,
u.CreatorId,
u.Active,
u.LastModificationTime,
u.LastModifierId,
u.InsertOrder,
u.ConcurrencyStamp,
//以下为JqGrid中必须的字段
u.Id //记录的唯一标识,可在插件中配置为其它字段,但是必须能作为记录的唯一标识用,不能重复
}),
total = pageCount, //总页数
page = jqGridParameter.Page, //当前页码
records = userCount //总记录数
}
);
}
启动项目后访问 /Identity/Manage/Users/Index 可以尝试使用。
结语
通过这次实践,深入了解了很多表达式树的相关知识,表达式树在编译流程中还算是高级结构了,耐点心还是能看懂,IL 才是真的晕,比原生汇编也好不到哪里去。C# 确实很有意思,入门简单,内部却深邃无比,在小白和大神手上完全是两种语言。Java 在 Java 8 时增加了 Stream 和 Lambda 表达式功能,一看就是在对标 Linq,不过那名字取的真是一言难尽,看代码写代码感觉如鲠在喉,相当不爽。由于 Stream 体系缺少表达式树,这种动态构造查询表达式的功能从一开始就不可能支持。再加上 Java 没有匿名类型,没有对象初始化器,每次用 Stream 就难受的一批,中间过程的数据结构也要专门写类,每个中间类还要独占一个文件,简直晕死。抄都抄不及格!
C# 引入 var 关键字核心是为匿名类型服务,毕竟是编译器自动生成的类型,写代码的时候根本没有名字,不用 var 用什么?简化变量初始化代码只是顺带的。结果 Java 又抄一半,还是最不打紧的一半,简化变量初始化代码。真不知道搞 Java 的那帮人在想些什么。
转载请完整保留以下内容并在显眼位置标注,未经授权删除以下内容进行转载盗用的,保留追究法律责任的权利!
本文地址:https://www.cnblogs.com/coredx/p/12423929.html
完整源代码:Github
里面有各种小东西,这只是其中之一,不嫌弃的话可以Star一下。
动态构造任意复杂的 Linq Where 表达式的更多相关文章
- Linq to Sql : 动态构造Expression进行动态查询
原文:Linq to Sql : 动态构造Expression进行动态查询 前一篇在介绍动态查询时,提到一个问题:如何根据用户的输入条件,动态构造这个过滤条件表达式呢?Expression<Fu ...
- [2014-12-30]如何动态构造Lambda表达式(动态构造Lambda查询条件表达式)
声明 本文对Lambda表达式的扩展,示例代码来源于网络. 场景描述 web开发查询功能的时候,如果查询条件比较多,就会遇到动态组合查询条件的情况.在手写sql的情况下,我们一般会根据传入的参数,针对 ...
- [C#.NET 拾遗补漏]13:动态构建LINQ查询表达式
最近工作中遇到一个这样的需求:在某个列表查询功能中,可以选择某个数字列(如商品单价.当天销售额.当月销售额等),再选择 小于或等于 和 大于或等于 ,再填写一个待比较的数值,对数据进行查询过滤. 如果 ...
- EntityFramework 动态构造排序 Func<IQueryable<T>, IOrderedQueryable<T>> Dynamic
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...
- LINQ查询表达式---------where子句
LINQ查询表达式---------where子句 where 子句用在查询表达式中,用于指定将在查询表达式中返回数据源中的哪些元素. 它将一个布尔条件(“谓词”)应用于每个源元素(由范围变量引用), ...
- C# LINQ查询表达式用法对应Lambda表达式
C#编程语言非常优美,我个人还是非常赞同的.特别是在学习一段时间C#后发现确实在它的语法和美观度来说确实要比其它编程语言强一些(也可能是由于VS编译器的加持)用起来非常舒服,而且对于C#我觉得他最优美 ...
- Linq专题之创建Linq查询表达式
本节我们主要介绍一下如何创建查询集合类型,关系数据库类型,DataSet对象类型和XML类型的数据源的Linq查询表达式. 下面在实例代码ReadyCollectionData()函数创建了准备的数据 ...
- Linq lamda表达式Single和First方法
让我们来看看如何对一个整数数组使用 Single 操作符.这个整数数组的每个元素代表 2 的 1 到 10 次方.先创建此数组,然后使用 Single 操作符来检索满足 Linq Lambda表达 ...
- 2.3 LINQ查询表达式中 使用select子句 指定目标数据
本篇讲解LINQ查询的三种形式: 查询对象 自定义查询对象某个属性 查询匿名类型结果 [1.查询结果返回集合元素] 在LINQ查询中,select子句和from子句都是必备子句.LINQ查询表达式必须 ...
随机推荐
- MySQL修改最大连接数的两个方法,偏爱第一种
总结MySQL修改最大连接数的两个方式 最大连接数是可以通过mysql进行修改的,mysql数据库修改最大连接数常用有两种方法,今天我们分析一下这两种方法之间的特点和区别,以便我们能更好的去维护m ...
- Matlab高级教程_第二篇:一个简单的混编例子
1. 常用的混编是MATLAB和VS两个编辑器之间的混编方式. 2. 因为MATLAB的核是C型语言,因此常见的混编方式是MATLAB和C型语言的混编. 3. 这里介绍一个简单的MATLAB语言混编成 ...
- 项目server中设置session timeout遇到的问题
RT:在项目server中的web.xml设置session timeout=10,当10分钟后,继续右键执行jsp文件,运行失败,如下图所示: 但是单独启动tomcat server后,在浏览器中输 ...
- 安装php7.2
1,yum源默认的版本太低了,手动安装有一些麻烦,所以可以采用yum的方式进行安装. 2,检查当前安装的PHP包yum list installed | grep php 如果有安装的PHP包,先删除 ...
- 好久不见,Java设计模式
引子 设计模式是很多程序员总结出来的最佳实践.曾经在刚开始写项目的时候学习过设计模式,在开发过程中,也主动或者被动的使用过.现在写代码虽说不会特意明确在用哪种设计模式,但潜移默化的写出来公认的最佳实践 ...
- python之time模块和hashlib模块
一.time模块 import time print(time.strftime('%Y-%m-%d %H:%M:%S'))#获取当前的格式化时间,time.strftime(format) prin ...
- web前端校招笔试题集锦
写一个求和的函数sum,达到下面的效果 // Should equal 15 sum(1, 2, 3, 4, 5); // Should equal 0 sum(5, null, -5); // Sh ...
- SHELL用法九(awk练习)
1.SHELL编程Awk语句案例实战 Awk主要是用于对文本文件进行处理,通常是逐行处理,其语法参数格式为, AWK常用参数.变量.函数详解如下: awk 'pattern + {action}' f ...
- RNA sequence单分子直测技术
生命组学 按照功能分类遗传物质,可能的分类有系统流.操作流.平衡流等等.下面是使用该理论解释DNA与RNA的关系: DNA和RNA有很大不同,DNA存储遗传信息,作为生命活动的最内核物质,如同操作系统 ...
- 通过命令行创建Django项目
只有安装的是pycharm专业版才可以直接在pycharm面板中直接创建Django项目 如果不是专业版,可以通过命令行创建Django项目 https://www.cnblogs.com/jiare ...