首页 文章

LINQ中的条件GroupBy()

提问于
浏览
5

我正在处理一个充满项目之间相似性的矩阵 . 我将这些保存为数据库中的对象列表 . Similarity对象如下所示:

public class Similarity
{
    public virtual Guid MatrixId { get; set; } //The id of the matrix the similarity is in
    public virtual Guid FirstIndex { get; set; } //The id of the item of the left side of the matrix
    public virtual Guid SecondIndex { get; set; } //The id of the item of the top side of the matrix
    public virtual double Similarity { get; set; } //The similarity
}

用户可以查看这些项目 . 我想检索用户已审阅的项目列表'similar' . 问题是我可以 FirstIndex 的id在 FirstIndexSecondIndex 中 . 我写了一些代码,它可以完成我想要的,但我想知道这是否可以在1个语句中实现 .

var itemsNotReviewed = Similarities.Where(x => !itemsReviewed.Contains(x.SecondIndex))
    .GroupBy(x => x.SecondIndex)
    .ToList();
itemsNotReviewed.AddRange(Similarities.Where(x => !itemsReviewed.Contains(x.FirstIndex))
     .GroupBy(x => x.FirstIndex)
     .ToList());

其中 itemsReviewed 是用户已审阅的项目的guid列表,其中 Similarities 是与用户已审阅的项目类似的所有项目的列表 . 我用这个函数检索该列表:

return (from Row in _context.SimilarityMatrix
        where itemIds.Contains(Row.FirstIndex) || itemIds.Contains(Row.SecondIndex)
        select Row)
        .Distinct()
        .ToList();

其中 itemIds 是用户已审阅的项目的guid列表 .

有没有办法根据Where子句分组第一个或第二个索引?

如果我要详细说明,请告诉我!

3 回答

  • 1

    根据我的理解,你有一个 Similarity 的清单,保证包含 FirstIndexSecondIndex itemsReviewed 列表中包含 FirstIndexSecondIndex 的项目 . 并且你需要使用 itemsReviewed 中包含的索引 not 来获取元素(如果有的话)(由于第一个约束它可能只是其中一个)并且由该索引分组 .

    上面简单的LINQ翻译就像这样:

    var itemsNotReviewed = Similarities
        .Where(item => !itemsReviewed.Contains(item.FirstIndex) || !itemsReviewed.Contains(item.SecondIndex))
        .GroupBy(item => !itemsReviewed.Contains(item.FirstIndex) ? item.FirstIndex : item.SecondIndex)
        .ToList();
    

    但它包含重复的 itemsReviewed.Contains 检查,这会对性能产生负面影响 .

    所以更好的变体是引入中间变量,最简单的方法是查询语法和 let 子句:

    var itemsNotReviewed =
        (from item in Similarities
         let index = !itemsReviewed.Contains(item.FirstIndex) ? 1 :
                !itemsReviewed.Contains(item.SecondIndex) ? 2 : 0
         where index != 0
         group item by index == 1 ? item.FirstIndex : item.SecondIndex)
        .ToList();
    
  • 3

    我会改变你原始列表的来源:

    _context.SimilarityMatrix.Where(Row => itemIds.Contains(Row.FirstIndex) || itemIds.Contains(Row.SecondIndex))
         .Select(r => new { r.MatrixId, r.FirstIndex, r.SecondIndex, r.Similarity, MatchingIndex = itemIds.Contains(r.FirstIndex) ? r.FirstIndex : r.SecondIndex })
         .Distinct()
         .ToList();
    

    这样您只需按匹配索引进行分组 .

    var itemsNotReviewed = Similarities.
    .GroupBy(x => x.MatchingIndex)
    .ToList();
    

    您可能希望在动态对象之后转换为Similarity类,或者只是更改类以包含匹配索引 .

    您可以通过以下方式将它们转换为您的相似类型:

    var itemsNotReviewed = Similarities.
    .GroupBy(x => x.MatchingIndex)
    .Select(g => new { g.Key, Values = g.Values.Select(d => new Similarity { MatrixId = d.MatrixId, FirstIndex = d.FirstIndex, SecondIndex = d.SecondIndex, Similarity = d.Similarity }).ToList() })
    .ToList();
    
  • 0

    关于什么

    (from x in Similarities
     let b2 = !itemsReviewed.Contains(x.SecondIndex)
     let b1 = !itemsReviewed.Contains(x.FirstIndex)
     where b1 || b2
     groupby b2 ? x.SecondIndex : x.FirstIndex into grp
     select grp)
    .ToList()
    

    let语句引入了一个存储boolean的新的tempoary变量 . 您当然也可以内联其他功能:

    (from x in (from Row in _context.SimilarityMatrix
                where itemIds.Contains(Row.FirstIndex) || itemIds.Contains(Row.SecondIndex)
                select Row)
               .Distinct()
               .ToList()
     let b2 = !itemsReviewed.Contains(x.SecondIndex)
     let b1 = !itemsReviewed.Contains(x.FirstIndex)
     where b1 || b2
     groupby b2 ? x.SecondIndex : x.FirstIndex into group
     select group)
    .ToList()
    

    如果您想使用非LINQ语法,您可能需要引入一些匿名类型:

    Similarities
    .Select(s => new 
    {
        b2 = !itemsReviewed.Contains(x.SecondIndex),
        b1 = !itemsReviewed.Contains(x.FirstIndex),
        s
    })
    .Where(a => a.b1 || a.b2)
    .GroupBy(a => a.b2 ? a.s.SecondIndex : a.s.FirstIndex, a => a.x) //edit: to get same semantics, you of course also need the element selector
    .ToList()
    

相关问题