【问题标题】:LINQ group by many valuesLINQ 按许多值分组
【发布时间】: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 语句来编写它。

标签: c# .net linq group-by


【解决方案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 - 是的,它可以。查询语法只是每种情况下方法语法的语法糖。我当然知道我更喜欢查询语法。
  • 非常感谢您的出色回答!我会尝试更多地了解查询语法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-10
  • 2015-12-06
相关资源
最近更新 更多