代码之家  ›  专栏  ›  技术社区  ›  Sweeper

如何简化这个在字符串中搜索关键字并按相关性排序的linq查询?

  •  1
  • Sweeper  · 技术社区  · 6 年前

    假设我有一些 MyObject 他们每个人都有一个 Description 财产。我有一个关键字列表,要用来搜索 我的对象 名单。我想按每个关键字的数量降序排列它们 描述 包含。

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

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

    示例关键字:

    "Boo", "Foo"
    

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

    "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... 而不是 关键词 .

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

    2 回复  |  直到 6 年前
        1
  •  1
  •   Krzysztof Skowronek    6 年前

    试试看:

        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
                        ;
    

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

        2
  •  2
  •   cgt_mky    6 年前

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

    不知道这算不算“更好”。