2012-04-24 35 views
19

Tengo tres (es posible tener más de 3-4 lista genérica, pero en este ejemplo, 3) listas genéricas.¿Cómo combinar más de dos listas genéricas en C# Zip?

List<string> list1 

List<string> list2 

List<string> list3 

todas las listas tienen el mismo número de elementos (mismos conteos).

que he usado para combinar dos listas con postal:

var result = list1.Zip(list2, (a, b) => new { 
    test1 = f, 
    test2 = b 
} 

he usado para foreach comunicado, para evitar foreach cada lista, al igual que

foreach(var item in result){ 
Console.WriteLine(item.test1 + " " + item.test2); 
} 

Cómo utilizar simmilary con cremallera para los tres listas?

Gracias

EDIT:

Quiero gusta:

List<string> list1 = new List<string>{"test", "otherTest"}; 

List<string> list2 = new List<string>{"item", "otherItem"}; 

List<string> list3 = new List<string>{"value", "otherValue"}; 

después postal (no sé método), quiero dar como resultado (en modo de depuración VS2010)

[0] { a = {"test"}, 
     b = {"item"}, 
     c = {"value"} 
    } 

[1] { a = {"otherTest"}, 
     b = {"otherItem"}, 
     c = {"otherValue"} 
    } 

¿Cómo hacer eso?

+0

Posible duplicado de [Crear elementos de 3 colecciones utilizando Linq] (http://stackoverflow.com/questions/5284315/create-items-from-3-collections-using-linq) – ensisNoctis

Respuesta

16

La forma más obvia para mí sería usar Zip dos veces.

Por ejemplo,

var results = l1.Zip(l2, (x, y) => x + y).Zip(l3, (x, y) => x + y); 

combinaría (añadir) los elementos de tres List<int> objetos.

Actualización:

se podría definir un nuevo método de extensión que actúa como un Zip con tres IEnumerable s, así:

public static class MyFunkyExtensions 
{ 
    public static IEnumerable<TResult> ZipThree<T1, T2, T3, TResult>(
     this IEnumerable<T1> source, 
     IEnumerable<T2> second, 
     IEnumerable<T3> third, 
     Func<T1, T2, T3, TResult> func) 
    { 
     using (var e1 = source.GetEnumerator()) 
     using (var e2 = second.GetEnumerator()) 
     using (var e3 = third.GetEnumerator()) 
     { 
      while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext()) 
       yield return func(e1.Current, e2.Current, e3.Current); 
     } 
    } 
} 

El uso (en el mismo contexto que el anterior) ahora se convierte en:

var results = l1.ZipThree(l2, l3, (x, y, z) => x + y + z); 

Del mismo modo, sus tres listas ahora se pueden combinar con:

var results = list1.ZipThree(list2, list3, (a, b, c) => new { a, b, c }); 
+0

Es una buena manera de hacerlo con variables (x, y) porque quiero usar la instrucción 'foreach' y obtener valores de cada elemento –

+0

¿Puedes echar un vistazo a la publicación EDITADA? Gracias –

+0

He actualizado mi respuesta; Espero que esto haga lo que necesitas. – GolfWolf

2
class Program 
{ 
    static void Main(string[] args) 
    { 
     List<string> list1 = new List<string> { "test", "otherTest" }; 
     List<string> list2 = new List<string> { "item", "otherItem" }; 
     List<string> list3 = new List<string> { "value", "otherValue" }; 

     var result = CombineListsByLayers(list1, list2, list3); 
    } 

    public static List<string>[] CombineListsByLayers(params List<string>[] sourceLists) 
    { 
     var results = new List<string>[sourceLists[0].Count]; 

     for (var i = 0; i < results.Length; i++) 
     { 
      results[i] = new List<string>(); 
      foreach (var sourceList in sourceLists) 
       results[i].Add(sourceList[i]); 
     } 
     return results; 
    } 
+0

A veces, un cigarro debe seguir siendo simplemente un cigarro. –

+0

Leo las otras respuestas que son mejores respuestas a su pregunta. pero, sinceramente, ¿por qué ir por algo que es tan ilegible y lleva 10 veces más escribir? –

+0

Me ayuda cuando leo la pregunta correctamente :), +1 de mí. – Phil

2

Se pueden combinar muchas listas en C# con métodos cascada de cremallera y clases anónimas y resultado tupla.

List<string> list1 = new List<string> { "test", "otherTest" }; 
List<string> list2 = new List<string> { "item", "otherItem" }; 
List<string> list3 = new List<string> { "value", "otherValue" }; 

IEnumerable<Tuple<string, string, string>> result = list1 
    .Zip(list2, (e1, e2) => new {e1, e2}) 
    .Zip(list3, (z1, e3) => Tuple.Create(z1.e1, z1.e2, e3)); 

El resultado es:

[0] 
{(test, item, value)} 
    Item1: "test" 
    Item2: "item" 
    Item3: "value" 
+2

En una nota lateral: es más fácil de usar [Tuple.Create] (https://msdn.microsoft.com/en-us/library/dd383822 (v = vs.110) .aspx), entonces no lo hace tiene que especificar los parámetros genéricos. – Maarten

2

Hay otra solución muy interesante que yo sepa.Es interesante sobre todo desde la perspectiva educativa, pero si uno tiene que realizar un relampago MUCHOS conteos de listas MUCHO, entonces también podría ser útil.

Este método anula la función LINQ SelectMany de .NET que es adoptada por una convención cuando utiliza la sintaxis de consulta LINQ. La implementación estándar SelectMany realiza un producto cartesiano. El anulado puede hacer zipping en su lugar. La implementación real podría ser:

static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, 
     Func<TSource, IEnumerable<TCollection>> selector, Func<TSource, TCollection, TResult> select) 
{ 
    using (var e1 = source.GetEnumerator()) 
     using (var e2 = selector(default(TSource)).GetEnumerator()) 
      while (true) 
       if (e1.MoveNext() && e2.MoveNext()) 
        yield return select(e1.Current, e2.Current); 
       else 
        yield break; 
} 

se ve un poco de miedo, pero es una lógica de comprimir el cual si está escrita una vez, se puede utilizar en muchos lugares y el código del cliente se ven bastante bien - se puede comprimir cualquier número de IEnumerable<T> utilizando el estándar de LINQ sintaxis de consulta:

var titles = new string[] { "Analyst", "Consultant", "Supervisor"}; 
var names = new string[] { "Adam", "Eve", "Michelle" }; 
var surnames = new string[] { "First", "Second", "Third" }; 

var results = 
    from title in titles 
    from name in names 
    from surname in surnames 
    select $"{ title } { name } { surname }"; 

Si a continuación, ejecuta:

foreach (var result in results) 
    Console.WriteLine(result); 

usted recibirá:

Analyst Adam First 
Consultant Eve Second 
Supervisor Michelle Third 

Debe mantener esta extensión privada dentro de su clase porque, de lo contrario, cambiará radicalmente el comportamiento del código circundante. Además, un nuevo tipo será útil para que no colide con el comportamiento LINQ estándar para IEnumerables.

Para los propósitos educativos He creado una vez un pequeño proyecto de C# con este método de extensión + pocos beneficios: https://github.com/lukiasz/Zippable

Además, si usted encuentra este interesante, recomiendo fuertemente Jon Skeet's Reimplementing LINQ to Objects articles.

¡Diviértete!

Cuestiones relacionadas