繁体   English   中英

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

[英]How can I make this LINQ search method handle more than two terms?

下面的搜索方法正常工作长达两个方面。

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestContains82343
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> tasks = new List<string>();
            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<string> SearchListWithSearchPhrase(List<string> tasks, string searchPhrase)
        {
            string[] parts = searchPhrase.Split(new char[] { ' ' });
            List<string> searchTerms = new List<string>();
            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<string> SearchListWithSearchPhrase
    (List<string> tasks, string searchPhrase)
{
    IEnumerable<string> searchTerms = searchPhrase.Split(' ')
                                                  .Select(x => x.Trim());
    IEnumerable<string> 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<string> 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<string> tasks = new List<string>
            {
                "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<string> SearchListWithSearchPhrase(List<string> 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<ItemsImLookingFor> items = new List<ItemsImLookingFor>();

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM