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

时间:2009-12-08 10:17:03

标签: c# linq

以下搜索方法适用 ,最多两个条款。

如何将其设置为动态,以便能够处理任意数量的搜索字词?

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;
            }

        }
    }
}

5 个答案:

答案 0 :(得分:5)

如何更换

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();

答案 1 :(得分:3)

只需反复拨打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()会对文化敏感 - 关于不区分大小写的匹配有各种警告:(有关详细信息,请查看this guidance on MSDN。我不确定对于不区分大小写的Contains有多少支持:(

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

以下是我写它的方式:

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

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

编辑:Aargh,我不敢相信我陷入了captured variable issue :(你需要创建foreach循环变量的副本,否则闭包将始终引用“当前”变量的值...在ToList执行时始终为 last 值:(

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

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();

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

用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();
    }

答案 4 :(得分:0)

为什么不在分割术语并将其保存到列表后使用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()
   );
}

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