2010-02-10 15 views
5

Tengo una colección IEnumerable<IEnumerable<T>> que quiero convertir a una colección de una dimensión. ¿Es posible lograr esto con un método de extensión genérico? En este momento estoy haciendo esto para lograrlo.Cómo convertir un IEnumerable <IEnumerable <T>> a un 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())); 
    } 
} 

Si no es posible obtener una solución genérica, ¿cómo puedo optimizar este de una manera elegante de moda.

+1

la pregunta del título es respondida aquí: http: // stackoverflow. com/questions/1590723/flatten-list-in-linq –

Respuesta

3

Aquí van:

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

Pero el código original produce una lista de cadenas, no una cadena ... –

+0

D'oh. De corrección. –

+1

¡Toda esta pregunta ha sido extraña! La redacción hizo una pregunta, el ejemplo le preguntó a otra. Y ha respondido una tercera pregunta diferente por completo, y me han aceptado ... Ya he publicado la respuesta correcta, y no tengo votos (no es que me importe, es divertido) –

18

Puede usar el método de extensión Enumerable.SelectMany para esto.

Si leo el código correctamente, el código para ese sería:

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

Editar: Como se ha comentado, el código anterior no se une a cada elemento de los subconjuntos en una cadena, como el original el código lo hace. El uso de los métodos incorporados, se puede hacer eso usando:

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

me ganó ... –

+0

¿Qué sucede si quiere que cada subconjunto sea un elemento de la nueva colección? Eso es lo que hago con String.Join ... –

+0

Esto no está bien, ignora el requisito de 'Unirse'. –

3

me gustaría utilizar personalmente Enumerable.SelectMany, como suggested by driis.

Sin embargo, si desea implementar esto por sí mismo, que sería mucho más limpio que hacer:

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

sí * SelectMany * es mejor, pero parece que mucha gente no sabe acerca de "rentabilidad de rendimiento", como lo demuestra esta pregunta. –

2

Usted hizo dos preguntas diferentes. El que describiste en el título ya fue respondido por drilis.

Pero su código de ejemplo es un problema diferente. Podemos refactorizarlo en etapas. Paso 1, a construir la lista subCombinations utilizando algún 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())); 
} 

Ahora el bucle externo, que nos deja con sólo esto:

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)); 
Cuestiones relacionadas