2016-12-06 74 views
1

的我有兩個的GroupBy結果的結果:LINQ的:集團若干的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<TKey, TSource>這樣的:

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對象。

我應該做一些類似的事情,還是有更好的(更容易掌握)的方法?

回答

1

通過使用Concat然後GroupBy並使用SelectMany平滑每個得到的分組,獲得期望的結果相對容易。

的問題是如何把它變成IGrouping<TKey, TElement>因爲沒有實現該接口的公共標準類,它是由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))); 
+0

此方法效果。甚至更快的方法,我使用的方法(創建一個字典並添加每個不存在的組,或addRange到現有的組。不知道你的靜態Create函數的優點是什麼,而不是隻使用構造函數 –

+0

Hi Harald,這只是爲了方便,類似於'Tuple.Create',以便讓編譯器推斷泛型參數。當然,如果您願意,您可以直接使用構造函數。 –