Linq:将扁平结构转换为分层结构

转换扁平结构的最简单,最有效的方法是什么:

object[][] rawData = new object[][] { { "A1", "B1", "C1" }, { "A1", "B1", "C2" }, { "A2", "B2", "C3" }, { "A2", "B2", "C4" } // .. more }; 

进入分层结构:

 class X { public X () { Cs = new List(); } public string A { get; set; } public string B { get; set; } public List Cs { get; private set; } } 

结果应该是这样的

 // pseudo code which describes structure: result = { new X() { A = "A1", B = "B1", Cs = { "C1", "C2" } }, new X() { A = "A2", B = "B2", Cs = { "C3", "C4" } } } 

优选使用Linq延伸方法。 目标类X可以被更改(例如,列表的公共设置器),只有在现在不可能/有用的情况下。

对于这个特殊情况:

  .GroupBy( x => new { a = x[0], b = x[1] } ) .Select( x => new { A = x.Key.a, B = x.Key.b, C = x.Select( c => c[2] ) }) 

如果您的层次结构的深度有限,那么这样的东西应该有效(如您的示例中只有三个级别A,B和C)。 我简化了你的X

 class X { public string A { get; set; } public string B { get; set; } public List Cs { get; set; } } 

然后,您可以根据需要多次使用嵌套的GroupBy (取决于层次结构的深度)。 将其重写为递归方法(对任意深层次结构都适用)也相对容易:

 // Group by 'A' rawData.GroupBy(aels => aels[0]).Select(a => // Group by 'B' a.GroupBy(bels => bels[1]).Select(b => // Generate result of type 'X' for the current grouping new X { A = a.Key, B = b.Key, // Take the third element Cs = b.Select(c => c[2]).ToList() })); 

这比其他解决方案更明确,但也许它更具可读性,因为它更直接地编码了这个想法……

如果X成员是字符串而Cs是私有集,而rawData是对象数组的数组,我会向X public X(string a, string b, List cs)添加构造函数public X(string a, string b, List cs) ,然后执行此代码

 var query = from row in rawData group row by new { A = row[0], B = row[1] } into rowgroup select new X((string)rowgroup.Key.A, (string)rowgroup.Key.B, rowgroup.Select(r => (string)r[2]).ToList()); 

这是基于以下原始数据

 object[][] rawData = new object[][] { new object[] { "A1", "B1", "C1" }, new object[] { "A1", "B1", "C2" }, new object[] { "A2", "B2", "C3" }, new object[] { "A2", "B2", "C4" } // .. more }; 

我想看看我是否可以在没有匿名实例的情况下编写此代码。 这不是太糟糕:

 IEnumerable myList = from raw0 in rawData group raw0 by raw0[0] into g0 let g1s = ( from raw1 in g0 group raw1 by raw1[1] ) from g1 in g1s select new X() { A = g0.Key, B = g1.Key, C = g1.Select(raw2 => raw2[2]).ToList() }