LINQ 按许多值分组

Posted

技术标签:

【中文标题】LINQ 按许多值分组【英文标题】:LINQ group by many values 【发布时间】:2021-07-25 10:39:43 【问题描述】:

我有多个 MyObject 实例,它们需要按它们的类型 MyType 分组(每个对象很多)。只需要每种类型的最新对象(由MyObject.Date 定义)。

以下代码通过嵌套的 foreach 语句实现了这一目标。

IEnumerable<MyObject> objects = ...;
var grouped = new Dictionary<MyType, MyObject>();
foreach (MyObject obj in objects.OrderBy(x => x.Date))
    foreach (MyType type in obj.Types)
        grouped[type] = obj;

如何使用GroupBy 使用LINQ 方法语法重写它?

【问题讨论】:

你的问题很难理解。 似乎您想要的是生成多个分组,即为每个可能的 MyType 值进行一个分组(而不是单个组,其中每个分组代表@987654328 的某种组合@ 值)。如果是这样,您应该能够简单地将可能的MyType 值的集合投影到基于每个这些值的分组中。 您尝​​试过什么?请修正您的问题,使其包含正确的minimal reproducible example,并详细说明该代码的作用、与您想要的有何不同以及... ...具体您需要什么帮助。还请确保您的描述是明确的(请注意,对输入和预期输出的详细解释有助于提供这种澄清,这是当前版本的问题所缺乏的)。 @peter-duniho 如果我的问题无法理解,我很抱歉。你是对的,我想为每个包含的 MyType 值生成一个分组。提供的代码已经实现了第一段中概述的目标,但我想知道如何使用 LINQ GroupBy 而不是嵌套的 foreach 语句来编写它。 【参考方案1】:

首先,您需要升级您的MyType 对象(如果您还没有这样做的话)以覆盖GetHashCodeEquals。如果不这样做,您不能将引用类型用作字典的键,否则它只会在内存中按引用分组。

这是我的你MyType

public class MyType

    public int Id;

    public override int GetHashCode()
    
        return this.Id.GetHashCode();
    

    public override bool Equals(object obj)
    
        if (obj is MyType other)
        
            return other.Id == this.Id;
        
        return base.Equals(obj);
    

接下来,我们需要一些示例数据来处理:

IEnumerable<MyObject> objects = new[]

    new MyObject()
    
        Date = new DateTime(1969, 7, 20),
        Types = new List<MyType>()
        
            new MyType()  Id = 1 ,
            new MyType()  Id = 2 ,
        
    ,
    new MyObject()
    
        Date = new DateTime(1986, 4, 26),
        Types = new List<MyType>()
        
            new MyType()  Id = 2 ,
            new MyType()  Id = 3 ,
        
    ,
;

现在,很简单:

var query =
    from obj in objects
    orderby obj.Date descending
    from type in obj.Types
    group obj by type into gts
    from gt in gts.Take(1)
    select new
    
        type = gts.Key,
        obj = gt
    ;
    
Dictionary<MyType, MyObject> grouped =
    query
        .ToDictionary(x => x.type, x => x.obj);

这给了我:


在方法语法中,查询变为:

Dictionary<MyType, MyObject> grouped =
    objects
        .OrderByDescending(obj => obj.Date)
        .SelectMany(obj => obj.Types, (obj, type) => new  obj, type )
        .GroupBy(x => x.type, x => x.obj)
        .SelectMany(gts => gts.Take(1), (gts, gt) => new  type = gts.Key, obj = gt )
        .ToDictionary(x => x.type, x => x.obj);

【讨论】:

感谢您的回答!这绝对是解决方案,但我对查询语法并不熟悉。也可以写成方法语法吗? @morrow - 是的,它可以。查询语法只是每种情况下方法语法的语法糖。我当然知道我更喜欢查询语法。 非常感谢您的出色回答!我会尝试更多地了解查询语法。

以上是关于LINQ 按许多值分组的主要内容,如果未能解决你的问题,请参考以下文章

SQL按多值字符串列中的不同值分组

Linq:按 OR 条件分组

LINQ - 按多个键分组未给出预期结果

linq.js 按javascript中的对象数组分组

LINQ 按多个字段分组 - 语法帮助

如何使用linq按多列分组[重复]