2016-08-04 147 views
1

有幾個類似的探測帖子,但沒有那樣做我想要的。如何動態GroupBy使用Linq

好了,所以可以想象,我有以下的數據結構(簡化這個LinqPad例如)

public class Row 
{ 
    public List<string> Columns { get; set; } 
} 

public List<Row> Data 
     => new List<Row> 
     { 
       new Row { Columns = new List<string>{ "A","C","Field3"}}, 
       new Row { Columns = new List<string>{ "A","D","Field3"}}, 
       new Row { Columns = new List<string>{ "A","C","Field3"}}, 
       new Row { Columns = new List<string>{ "B","D","Field3"}}, 
       new Row { Columns = new List<string>{ "B","C","Field3"}}, 
       new Row { Columns = new List<string>{ "B","D","Field3"}}, 
     }; 

對於屬性「數據」時,用戶將告訴我哪列序號到的GroupBy;他們可能會說「不按任何分組」,或者他們可能會說「按列[1]」或「按列[0]分組」列[1]「。

如果我想組由單一的專欄中,我可以使用:

var groups = Data.GroupBy(d => d.Columns[i]); 

如果我想組由2列,我可以使用:

var groups = Data.GroupBy(d => new { A = d.Columns[i1], B = d.Columns[i2] }); 

然而,數列是可變的(零 - >很多);數據可能包含數百個列,用戶可能想要GroupBy數十列。

所以問題是,如何在運行時(動態)創建此GroupBy?

感謝

格里夫

+0

您可以用某種方式構建Lambda表達式[非常類似於有關動態OrderBy的非常類似問題的答案](http://stackoverflow.com/a/233505/424129)。 –

回答

2

與那數據結構你要求什麼是相對容易的。

開始通過實現自定義IEqualityComparer<IEnumerable<string>>

public class ColumnEqualityComparer : EqualityComparer<IEnumerable<string>> 
{ 
    public static readonly ColumnEqualityComparer Instance = new ColumnEqualityComparer(); 
    private ColumnEqualityComparer() { } 
    public override int GetHashCode(IEnumerable<string> obj) 
    { 
     if (obj == null) return 0; 
     // You can implement better hash function 
     int hashCode = 0; 
     foreach (var item in obj) 
      hashCode ^= item != null ? item.GetHashCode() : 0; 
     return hashCode; 
    } 
    public override bool Equals(IEnumerable<string> x, IEnumerable<string> y) 
    { 
     if (x == y) return true; 
     if (x == null || y == null) return false; 
     return x.SequenceEqual(y); 
    } 
} 

現在你可以有這樣的方法:

public IEnumerable<IGrouping<IEnumerable<string>, Row>> GroupData(IEnumerable<int> columnIndexes = null) 
{ 
    if (columnIndexes == null) columnIndexes = Enumerable.Empty<int>(); 
    return Data.GroupBy(r => columnIndexes.Select(c => r.Columns[c]), ColumnEqualityComparer.Instance); 
} 

注意分組Key類型爲IEnumerable<string>,幷包含由指定的選擇行值columnIndexes參數,這就是爲什麼我們需要一個自定義的相等比較器(否則它們將通過引用進行比較,這不會產生所需的行爲)。

例如,由列0和2組你可以使用這樣的事情:

var result = GroupData(new [] { 0, 2 }); 

傳遞null或空columnIndexes將有效地產生一個組,即沒有分組。

0

你可以使用一個遞歸函數創建動態lambdaExpression。但是你必須在函數中定義HardCode列。