【问题标题】:Linq: Group the results of several GroupByLinq:对几个GroupBy的结果进行分组
【发布时间】:2016-12-06 09:31:20
【问题描述】:

我有两个GroupBy的结果:

IEnumerable<IGrouping<long, MyClass>> result1 = ...;
IEnumerable<IGrouping<long, MyClass>> result2 = ...;

我想把它们组合成一个序列。 result2 中的某些元素可能具有 IGrouping 键,它们也是 result1 中的键。所以标准的Enumerable.Concat 不起作用:

IEnumerable<IGrouping<long, MyClass>> result = result1.Concat(result2);

具有相同键的项目在结果序列中被提及两次。显然我需要一个特殊的Concat 来为IGrouping&lt;TKey, TSource&gt; 像这样:

public static IEnumerable<IGrouping<TKey, TSource>> Concat<TSource, TKey>
    (this IEnumerable<IGrouping<TKey, TSource>> first,
          IEnumerable<IGrouping<TKey, TSource>> second)

我可以取消组中的所有元素并重新组合它们,但这当然是一种浪费。

我看过source code of Enumerable.GroupBy。该方法创建一个 GroupedEnumerable 对象,该对象将在枚举 GroupedEnumerable 后立即创建一个 Lookup 对象。

我应该做类似的事情,还是有更好(更容易掌握)的方法?

【问题讨论】:

    标签: c# linq group-by


    【解决方案1】:

    通过使用Concat 后跟GroupBy 并使用SelectMany 展平每个结果分组,获得所需的结果相对容易。

    问题是如何将其转换为IGrouping&lt;TKey, TElement&gt;,因为没有实现该接口的公共标准类,它由GroupByToLookup 实现返回,并且也没有GroupBy 允许我们需要的重载.所以我们需要自己实现,幸运的是这很简单:

    class Grouping<TKey, TElement> : IGrouping<TKey, TElement>
    {
        IEnumerable<TElement> elements;
        public Grouping(TKey key, IEnumerable<TElement> elements)
        {
            this.Key = key;
            this.elements = elements;
        }
        public TKey Key { get; }
        public IEnumerator<TElement> GetEnumerator() => elements.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
    
    public static class Grouping
    {
        public static IGrouping<TKey, TElement> Create<TKey, TElement>(TKey key, IEnumerable<TElement> elements) =>
            new Grouping<TKey, TElement>(key, elements);
    }
    

    现在有问题的方法的实现可能是这样的:

    return first.Concat(second)
        .GroupBy(g => g.Key, (key, gg) => Grouping.Create(key, gg.SelectMany(g => g)));
    

    【讨论】:

    • 此方法有效。甚至比我使用的方法更快(创建一个字典 并添加每个不存在的组,或将添加范围添加到现有组。不确定静态 Create 函数的优势是什么,而不仅仅是使用构造函数
    • 嗨 Harald,这只是为了方便,类似于Tuple.Create,以便让编译器推断通用参数。当然如果你愿意,你可以直接使用构造函数。
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多