c# - 包含多个关键字的条件的 Lambda/Linq
问题描述
我必须列出
- 带有评论字段的主列表
- 要搜索的关键字列表。
我想在每条记录的每个评论字段中搜索关键字,在 SQL 中如下所示
select * from MainList
where Comment like '%keyword1%'
or Comment like '%keyword2%'
... so on until the last keyword.
到目前为止,我已经看到了示例,但通常一次只针对单个关键字,例如LINQ 与非 lambda 用于任何包含
我想要的是一次在 MainList 中的每条记录中搜索我的任何关键字的任何实例。就像是:
var newList = MainList.Where(m => m.Comments.Contains(purposes))
我更喜欢使用 lambda 语法,但如果不可能,linq 也可以。
解决方案
添加了可以帮助生成此类谓词的扩展方法。用法很简单:
var newList = MainList
.FilterByItems(keywords, (m, k) => m.Comments.Contains(k), true)
.ToList();
和实施:
public static class QueryableExtensions
{
public static IQueryable<T> FilterByItems<T, TItem>(this IQueryable<T> query, IEnumerable<TItem> items,
Expression<Func<T, TItem, bool>> filterPattern, bool isOr)
{
Expression predicate = null;
foreach (var item in items)
{
var itemExpr = Expression.Constant(item);
var itemCondition = ExpressionReplacer.Replace(filterPattern.Body, filterPattern.Parameters[1], itemExpr);
if (predicate == null)
predicate = itemCondition;
else
{
predicate = Expression.MakeBinary(isOr ? ExpressionType.OrElse : ExpressionType.AndAlso, predicate,
itemCondition);
}
}
predicate ??= Expression.Constant(false);
var filterLambda = Expression.Lambda<Func<T, bool>>(predicate, filterPattern.Parameters[0]);
return query.Where(filterLambda);
}
class ExpressionReplacer : ExpressionVisitor
{
readonly IDictionary<Expression, Expression> _replaceMap;
public ExpressionReplacer(IDictionary<Expression, Expression> replaceMap)
{
_replaceMap = replaceMap ?? throw new ArgumentNullException(nameof(replaceMap));
}
public override Expression Visit(Expression exp)
{
if (exp != null && _replaceMap.TryGetValue(exp, out var replacement))
return replacement;
return base.Visit(exp);
}
public static Expression Replace(Expression expr, Expression toReplace, Expression toExpr)
{
return new ExpressionReplacer(new Dictionary<Expression, Expression> { { toReplace, toExpr } }).Visit(expr);
}
public static Expression Replace(Expression expr, IDictionary<Expression, Expression> replaceMap)
{
return new ExpressionReplacer(replaceMap).Visit(expr);
}
public static Expression GetBody(LambdaExpression lambda, params Expression[] toReplace)
{
if (lambda.Parameters.Count != toReplace.Length)
throw new InvalidOperationException();
return new ExpressionReplacer(Enumerable.Range(0, lambda.Parameters.Count)
.ToDictionary(i => (Expression) lambda.Parameters[i], i => toReplace[i])).Visit(lambda.Body);
}
}
}
推荐阅读
- android - 无法读取 sim 号码
- apollo - com.apollographql.apollo.exception.ApolloHttpException:HTTP 500 内部服务器错误
- javascript - React.js - JSON 中的值未定义
- css - 将响应式图像与页面底部中心对齐?应该使用 flexbox 吗?
- javascript - 数组以另一种方式包含字符串
- c++ - std::thread 和 tbb::task_group 之间的线程 ID 重用导致 OpenMP 中的死锁
- typescript - 如何使用 typescript 创建 react-native 自定义视图
- vue.js - Vue:拥有根组件与仅将组件放在 div 根中有什么区别?
- visualization - 在 MicroStrategy Reporting Tool (MSTR) 中,Numeric 提示、Big decimal 提示和 Long 提示有什么区别?
- jupyter-notebook - Jupyter-notebook ModuleNotFoundError:没有名为“游侠”的模块