【问题标题】:Check if string contains a list of strings in any order检查字符串是否包含任何顺序的字符串列表
【发布时间】:2015-03-24 11:24:18
【问题描述】:

基本上,我有一个产品列表和一个搜索选项。当搜索多个单词时,我想返回包含按任何顺序搜索的所有单词的任何产品。

因此,如果用户搜索“green shirt”,返回的列表将包括“green t-shirt large”、“t-shirt green medium”等。我的(坏)代码:

public List<Products> FindProductsByName(string query, int limit)
{
    string[] words = query.ToLower().Split(' ');
    List<Products> products = new List<Products>();
    foreach (var word in words)
    {
        products.AddRange(All.Where(x => x.ProductName.ToLower().Contains(word)).Take(limit).ToList());
        //this will return all products which contains ANY word in the searched word list
    }
    return products;
}

所以基本上,我想要

All.Where(x => x.Productname.ToLower().Contains(words[0]) && x.Productname.ToLower().Contains(words[1]) ...

但我不知道搜索查询中有多少字。我觉得这应该很容易,但我的大脑今天不工作。我错过了什么?

【问题讨论】:

  • 你能发一个dotnetfiddle吗?小提琴应该是一个工作示例。
  • 将两个字符串拆分成一个单词列表;然后对两个字符串进行排序并运行 *merge-comparison。
  • Set operations 文章应该可以帮助您选择适合您需要的两组操作。

标签: c# string linq contains


【解决方案1】:

我想你正在寻找 Linq 方法Intersect()

dotnetfiddle 上的工作示例。

代码:

public static void Main()
{
    var list = FindProductsByName("green shirt", 2);
    foreach (var products in list)
        Console.WriteLine(products.ProductName);
}

public static IEnumerable<Products> FindProductsByName(string query, int limit)
{
    string[] words = query.ToLower().Split(' ');
    List<Products> products = new List<Products>
    {
        new Products { ProductName = "green t-shirt large" },
        new Products { ProductName = "t-shirt green medium" },
        new Products { ProductName = "t-shirt red" }
    };
    return
        (from p in products
        let productsComponent = p.ProductName.Split(' ') // you should make a list of keyword in Products instead
        where productsComponent.Intersect(words).Any()
        select p).Take(limit);
}

public class Products
{
    public string ProductName { get; set; }
}

输出:

green t-shirt large
t-shirt green medium

编辑:我忘了添加limit。所以我添加了它。

【讨论】:

  • 很好的例子,这看起来可行,但在你发布之前我已经解决了这个问题。再次感谢。
  • 没问题。您可以将其标记为已解决。祝你有美好的一天。
  • @tarnold86 可能是为了防止其他人对此投反对票,您应该编辑您的问题,展示您 Solved 的修复
  • @MethodMan 完成。这在任何人评论之前就被否决了,不知道为什么。
  • 你的更快,因为我使用了 ToList() 函数。此外,您的版本没有在产品列表字符串上运行 .ToLower() 。更新两者以返回 IEnumerable 并再次运行它。它们都非常具有可比性。
【解决方案2】:

在 aloisdg 发布他出色的解决方案之前,我能够提出一个可行的解决方案。这是我的工作代码:

string[] words = query.ToLower().Split(' ');
var products = from p in All select p;
foreach (var word in words)
{
    products = products.Where(x => x.ProductName.ToLower().Contains(word));
}
return products.Take(limit).ToList();

我想避免将产品名称分解为字符串数组并使用 intersect 命令,因为表中有大约 30,000 个产品,这会减慢速度。

谢谢大家的帮助。

【讨论】:

  • var products = from p in All select p;你在这里做什么?
  • 您自己设法解决了问题是一件好事。我对我们的解决方案进行了基准测试,我的速度更快。如果您需要一些性能...
  • var products = from p in All select p;这一行正在设置查询,因此我们可以为数组中的每个单词添加一个 where 子句。
  • 所以您正在使用延迟执行。好的。
【解决方案3】:

你可以使用LINQ方法All

products.Where(p=> words.All(w=> p.ProductName.Contains(w));

我接受了 aloisdg dotnetfiddle 并更新了我的答案。

【讨论】:

    猜你喜欢
    • 2015-03-25
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多