如何使这个LINQ搜索方法处理两个以上的术语?

以下搜索方法适用于最多两个术语。

如何使其动态化以便能够处理任意数量的搜索条件?

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TestContains82343 { class Program { static void Main(string[] args) { List tasks = new List(); tasks.Add("Add contract to Customer."); tasks.Add("New contract for customer."); tasks.Add("Create new contract."); tasks.Add("Go through the old contracts."); tasks.Add("Attach files to customers."); var filteredTasks = SearchListWithSearchPhrase(tasks, "contract customer"); filteredTasks.ForEach(t => Console.WriteLine(t)); Console.ReadLine(); } public static List SearchListWithSearchPhrase(List tasks, string searchPhrase) { string[] parts = searchPhrase.Split(new char[] { ' ' }); List searchTerms = new List(); foreach (string part in parts) { searchTerms.Add(part.Trim()); } switch (searchTerms.Count()) { case 1: return (from t in tasks where t.ToUpper().Contains(searchTerms[0].ToUpper()) select t).ToList(); case 2: return (from t in tasks where t.ToUpper().Contains(searchTerms[0].ToUpper()) && t.ToUpper().Contains(searchTerms[1].ToUpper()) select t).ToList(); default: return null; } } } } 

如何更换

 switch (searchTerms.Count()) { case 1: return (from t in tasks where t.ToUpper().Contains(searchTerms[0].ToUpper()) select t).ToList(); case 2: return (from t in tasks where t.ToUpper().Contains(searchTerms[0].ToUpper()) && t.ToUpper().Contains(searchTerms[1].ToUpper()) select t).ToList(); default: return null; } 

通过

 (from t in tasks where searchTerms.All(term => t.ToUpper().Contains(term.ToUpper())) select t).ToList(); 

只是反复调用Where …我已经改变了对searchTerms的处理,使其略微更加LINQ-y 🙂

 public static List SearchListWithSearchPhrase (List tasks, string searchPhrase) { IEnumerable searchTerms = searchPhrase.Split(' ') .Select(x => x.Trim()); IEnumerable query = tasks; foreach (string term in searchTerms) { // See edit below String captured = term; query = query.Where(t => t.ToUpper().Contains(captured)); } return query.ToList(); } 

您应该注意,默认情况下, ToUpper()将对文化敏感 – 关于不区分大小写的匹配有各种警告:(有关详细信息,请查看MSDN上的此指南 。我不确定它有多少支持不区分大小写但Contains 🙁

编辑:我喜欢konamiman的答案,虽然看起来它的分裂与原始代码有些不同。 All肯定是一个有用的LINQ运算符,了解…

这是我写它的方式:

 return tasks.Where(t => searchTerms.All(term => t.ToUpper().Contains(term))) .ToList(); 

(当一个运算符应用于外部查询时,我通常不使用查询表达式。)

编辑:Aargh,我不敢相信我陷入了捕获的变量问题 :(你需要创建一个foreach循环变量的副本,否则闭包将始终引用变量的“当前”值…这将永远是执行ToList最后一个值:(

编辑:请注意,到目前为止,所有内容在多次上限每个任务方面都是低效的。 这在现实中可能很好,但你可以通过使用这样的东西避免它:

 IEnumerable query = tasks.Select (t => new { Original = t, Upper = t.ToUpper }); return query.Where(task => searchTerms.All(term => task.Upper.Contains(term))) .Select(task => task.Original) .ToList(); 

目前无法测试代码,但您可以执行与此类似的操作:

 from t in tasks let taskWords=t.ToUpper().Split(new char[] { ' ' }); where searchTerms.All(term => taskWords.Contains(term.ToUpper())) select t 

用for循环替换switch语句:)

  [TestMethod] public void TestSearch() { List tasks = new List { "Add contract to Customer.", "New contract for customer.", "Create new contract.", "Go through the old contracts.", "Attach files to customers." }; var filteredTasks = SearchListWithSearchPhrase(tasks, "contract customer new"); filteredTasks.ForEach(Console.WriteLine); } public static List SearchListWithSearchPhrase(List tasks, string searchPhrase) { var query = tasks.AsEnumerable(); foreach (var term in searchPhrase.Split(new[] { ' ' })) { string s = term.Trim(); query = query.Where(x => x.IndexOf(s, StringComparison.InvariantCultureIgnoreCase) != -1); } return query.ToList(); } 

为什么不在分割术语并将其保存到列表后使用foreach和AddRange()。

 List items = new List(); // search for terms foreach(string term in searchTerms) { // add users to list items.AddRange(dbOrList( item => item.Name.ToLower().Contains(str)).ToList() ); } 

这应该适用于任何数量的条款。