2010-02-10 4 views
5

J'ai une collection IEnumerable<IEnumerable<T>> que je veux convertir en une collection de dimension unique. Est-il possible d'y parvenir avec une méthode d'extension générique? En ce moment je fais ceci pour l'accomplir.Comment convertir un IEnumerable <IEnumerable <T>> en IEnumerable <T>

List<string> filteredCombinations = new List<string>(); 

//For each collection in the combinated results collection 
foreach (var combinatedValues in combinatedResults) 
{ 
    List<string> subCombinations = new List<string>(); 
    //For each value in the combination collection 
    foreach (var value in combinatedValues) 
    { 

     if (value > 0) 
     { 
      subCombinations.Add(value.ToString()); 
     } 
    } 
    if (subCombinations.Count > 0) 
    { 
     filteredCombinations.Add(String.Join(",",subCombinations.ToArray())); 
    } 
} 

S'il n'est pas possible d'obtenir une solution générique, comment puis-je l'optimiser de façon élégante?

+1

la question dans le titre réponse ici: http: // stackoverflow. com/questions/1590723/flatten-list-in-linq –

Répondre

3

Ici, vous allez:

var strings = combinedResults.Select 
    (
     c => c.Where(i => i > 0) 
     .Select(i => i.ToString()) 
    ).Where(s => s.Any()) 
    .Select(s => String.Join(",", s.ToArray()); 
+0

Mais le code original produit une liste de chaînes, pas une chaîne ... –

+0

D'oh. Corriger –

+1

Toute cette question a été bizarre! Le libellé posait une question, l'exemple en demandait un autre. Et vous avez répondu à une troisième question complètement différente, et j'ai été acceptée ... J'ai déjà posté la bonne réponse, et je n'ai pas de votes (pas que cela me dérange, c'est juste amusant.) –

18

Vous pouvez utiliser la méthode d'extension Enumerable.SelectMany pour cela.

Si je lis votre code correctement, le code pour ce serait:

var filteredCombinations = combinatedResults.SelectMany(o => o) 
    .Where(value => value > 0) 
    .Select(v => v.ToString()); 

Modifier: Comme commenté, le code ci-dessus ne se joint pas chaque élément des sous-ensembles à une chaîne, comme l'original le code fait. À l'aide des méthodes intégrées, vous pouvez le faire en utilisant:

var filteredCombinations = combinatedResults 
    .Where(resultSet => resultSet.Any(value => value > 0) 
    .Select(resultSet => String.Join(",", 
     resultSet.Where(value => value > 0) 
        .Select(v => v.ToString()).ToArray())); 
+0

battu moi ... –

+0

Et si vous voulez que chaque sous-ensemble soit un élément de la nouvelle collection? C'est ce que je fais avec le String.Join ... –

+0

Ce n'est pas correct - il ignore l'exigence 'Join'. –

3

Personnellement, j'utiliser Enumerable.SelectMany, comme suggested by driis.

Cependant, si vous vouliez mettre en œuvre vous-même, il serait beaucoup plus propre à faire:

IEnumerable<T> MakeSingleEnumerable<T>(IEnumerable<IEnumerable<T>> combinatedResults) 
{ 
    foreach (var combinatedValues in combinatedResults) { 
     foreach (var value in combinatedValues) 
       yield return value; 
    } 
} 
+0

oui * SelectMany * est mieux, mais il semble que beaucoup de gens ne connaissent pas le «rendement de rendement» - comme en témoigne cette question. –

2

Vous avez posé deux questions différentes. Celui que vous avez décrit dans le titre est déjà répondu par drilis.

Mais votre exemple de code est un problème différent. Nous pouvons le refactoriser par étapes. Étape 1, construire la liste à l'aide subCombinations certains Linq:

List<string> filteredCombinations = new List<string>(); 

//For each collection in the combinated results collection 
foreach (var combinatedValues in combinatedResults) 
{ 
    var subCombinations = combinatedValues.Where(v => v > 0) 
              .Select(v => v.ToString()) 
              .ToList(); 

    if (subCombinations.Count > 0) 
     filteredCombinations.Add(string.Join(",",subCombinations.ToArray())); 
} 

Maintenant la boucle extérieure, nous laissant avec ceci:

var filteredCombinations = combinatedResults 
    .Select(values => values.Where(v => v > 0) 
          .Select(v => v.ToString()) 
          .ToArray()) 
    .Where(a => a.Count > 0) 
    .Select(a => string.Join(",", a)); 
Questions connexes