如何简化此LINQ查询以搜索字符串中的关键字并按相关性对其进行排序?

时间:2018-06-14 11:21:19

标签: c# linq linq-to-objects

假设我有一些MyObject个,每个都有一个Description属性。我有一个关键字列表,我想用它来搜索MyObject列表。我想按照每个Description包含的关键字数量按降序排序。

示例输入(仅显示Description属性,请注意初始顺序):

"Foo Bar"
"Foo Boo"
"Bar Bar"

示例关键字:

"Boo", "Foo"

示例输出(仅显示Description属性,请注意最终顺序):

"Foo Boo" (matches 2 keywords)
"Foo Bar" (matches 1 keyword)

“Bar”“Bar”不在结果中,因为它匹配0个关键字。

我目前正在使用这种非常复杂的方法链:

return keywords.SelectMany(
    x => MyObjects.Where(y => y.Description.ToLowerInvariant().Contains(x.ToLowerInvariant()))
    )
    .GroupBy(x => x)
    .OrderByDescending(x => x.Count())
    .Select(x => x.Key).ToList();

如您所见,我首先选择keywords。我认为作为代码的读者,您可能希望首先在MyObjects上看到一些转换。通常当我编写LINQ时,我会尝试在脑海中看到操作的样子。看到正在转换的关键字只是让人感到反直觉。我也不喜欢SelectMany中的嵌套查询,因为它使查询语法看起来非常难看:

var query = from keyword in keywords
            from matchedObjects in (from obj in MyObjects where obj.Description.ToLowerInvariant().Contains(keyword.ToLowerInvariant()) select obj)
            group matchedObjects by matchedObjects into sameObjects
            orderby sameObjects.Count() descending
            select sameObjects.Key;
return query.ToList();

如何改进LINQ查询?理想的情况是:

  • 没有嵌套查询
  • MyObjects.SomeLINQOperation...而不是keywords开头。

我希望有一种更容易/更直观的方式,因为这似乎是一件微不足道的事情,但我也会接受,如果提供解释,没有更简单的方法。

2 个答案:

答案 0 :(得分:2)

results = myObjects.OrderByDescending(myObject => keywords.Where(keyword => myObject.Description.Contains(keyword)).Count());

给你你需要的东西?

编辑:

var temp = myObjects.Where(myObject => keywords.Any(keyword => myObject.Description.Contains(keyword)))
            .OrderByDescending(myObject => keywords.Where(keyword => myObject.Description.Contains(keyword)).Count());

不确定这是否更好'。

答案 1 :(得分:1)

试试:

    var objects = new[]{
                    new MyObject{Description = "Foo Bar"},
                    new MyObject{Description = "Foo Boo"},
                    new MyObject{Description = "Foo Bee"},
                    new MyObject{Description = "Bar Bee"},
                    new MyObject{Description = "Boo Bee"},
                };
                var keywords = new[] { "Foo", "Bar" };
                var results = objects
                    .GroupBy(x => keywords.Where(
                                          keyword => x.Description.Contains(keyword) 
                                          ).Count()
                    )
                    .Where(x => x.Key > 0) // discard no matches
//                    .OrderByDescending(x => x.Count()) // order by mathing objects count
                    .OrderByDescending(x => x.Key)
//                   .ToDictionary(x => x.Key, x => x.ToArray())
                     .Select(x => new {Count = x.Key, Objects = x.ToArray()}).ToList(); // or create anonymous type
                    ;

它按匹配计数对象进行分组,不丢弃匹配项并将最多匹配项放在顶部