Linq: Conversion d’une structure plate en hiérarchie

Quel est le moyen le plus simple et le plus efficace de convertir une structure plate:

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

dans une structure hiérarchique:

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

le résultat devrait ressembler à ceci

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

De préférence en utilisant les méthodes d’extension Linq. La classe cible X pourrait être modifiée (par exemple, un organisateur public pour la liste), uniquement si cela n’est pas possible / utile dans l’état actuel des choses.

pour ce cas particulier:

  .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] ) }) 

Quelque chose comme ceci devrait fonctionner si la profondeur de votre hiérarchie est limitée (comme dans votre exemple où vous n’avez que trois niveaux A, B et C). J’ai simplifié un peu votre X :

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

Vous pouvez ensuite utiliser GroupBy nested autant de fois que nécessaire (en fonction de la profondeur de la hiérarchie). Il serait également relativement facile de réécrire cela en une méthode récursive (qui fonctionnerait pour des hiérarchies arbitrairement profondes):

 // 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() })); 

Ceci est plus explicite que les autres solutions ici, mais peut-être sera-t-il plus lisible car il s’agit d’un codage plus simple de l’idée …

Les membres X étant des chaînes et les C étant un ensemble privé, et rawData étant un tableau de tableaux d’objects, je voudrais append un constructeur à X public X(ssortingng a, ssortingng b, List cs) , puis effectuer ce code.

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

Ceci est sur les données brutes suivantes

 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 }; 

Je voulais voir si je pouvais écrire ceci sans instances anonymes. Ce n’est pas si mal:

 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() }