2010-03-11 11 views
11
función

de Python zip hace lo siguiente:Cómo hacer el zip de Python en C#?

a = [1, 2, 3] 
b = [6, 7, 8] 
zipped = zip(a, b) 

resultado

[[1, 6], [2, 7], [3, 8]] 
+2

Tenga en cuenta que zip puede tomar cualquier cantidad de argumentos, no solo dos, como en este ejemplo. Las respuestas hasta ahora se centran en este caso de dos iterables, me parece a mí. –

+0

@Jeffrey bien recordado. –

Respuesta

7

¿Qué tal this?

C# 4.0 LA NUEVA LINQ OPERADOR postal

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
     this IEnumerable<TFirst> first, 
     IEnumerable<TSecond> second, 
     Func<TFirst, TSecond, TResult> func); 
+3

El nombre es el mismo, pero la acción es completamente diferente. El Zip de Linq() se puede usar para producir efecto python-zip en 2 secuencias de entrada, pero no tiene nada que ver con más de 2 secuencias. –

2

Solución 1:

IEnumerable<KeyValuePair<T1, T2>> Zip<T1, T2>(
    IEnumerable<T1> a, IEnumerable<T2> b) 
{ 
    var enumeratorA = a.GetEnumerator(); 
    var enumeratorB = b.GetEnumerator(); 
    while (enumeratorA.MoveNext()) 
    { 
     enumeratorB.MoveNext(); 
     yield return new KeyValuePair<T1, T2> 
     (
      enumeratorA.Current, 
      enumeratorB.Current 
     ); 
    } 
} 
5

Solución 2: Al igual que en C# 4.0 Zip, pero se puede usar en C# 3,0

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
     this IEnumerable<TFirst> first, 
     IEnumerable<TSecond> second, 
     Func<TFirst, TSecond, TResult> func) 
    { 
     using(var enumeratorA = first.GetEnumerator()) 
     using(var enumeratorB = second.GetEnumerator()) 
     { 
      while (enumeratorA.MoveNext()) 
      { 
       enumeratorB.MoveNext(); 
       yield return func(enumeratorA.Current, enumeratorB.Current); 
      } 
     } 
    } 
+0

arroja excepciones cuando el segundo es más corto que el primero, como se esperaba –

+6

Ha olvidado deshacerse de sus enumeradores. –

+0

@Eric gracias por la corrección. Edité la respuesta –

0

yo sólo he encontrado con el mismo problema. La biblioteca .NET no ofrece la solución, así que lo hice yo mismo. Aquí está mi solución.

El método Pivot se realiza como extensión a IEnumerable<IEnumerable<T>>. Requiere que todos los elementos de las secuencias sean del mismo tipo T.

public static class LinqUtil 
{ 
    /// <summary> 
    /// From a number of input sequences makes a result sequence of sequences of elements 
    /// taken from the same position of each input sequence. 
    /// Example: ((1,2,3,4,5), (6,7,8,9,10), (11,12,13,14,15)) --> ((1,6,11), (2,7,12), (3,8,13), (4,9,14), (5,10,15)) 
    /// </summary> 
    /// <typeparam name="T">Type of sequence elements</typeparam> 
    /// <param name="source">source seq of seqs</param> 
    /// <param name="fillDefault"> 
    /// Defines how to handle situation when input sequences are of different length. 
    ///  false -- throw InvalidOperationException 
    ///  true -- fill missing values by the default values for the type T. 
    /// </param> 
    /// <returns>Pivoted sequence</returns> 
    public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> source, bool fillDefault = false) 
    { 
     IList<IEnumerator<T>> heads = new List<IEnumerator<T>>(); 

     foreach (IEnumerable<T> sourceSeq in source) 
     { 
      heads.Add(sourceSeq.GetEnumerator()); 
     } 

     while (MoveAllHeads(heads, fillDefault)) 
     { 
      yield return ReadHeads(heads); 
     } 
    } 

    private static IEnumerable<T> ReadHeads<T>(IEnumerable<IEnumerator<T>> heads) 
    { 
     foreach (IEnumerator<T> head in heads) 
     { 
      if (head == null) 
       yield return default(T); 
      else 
       yield return head.Current; 
     } 
    } 

    private static bool MoveAllHeads<T>(IList<IEnumerator<T>> heads, bool fillDefault) 
    { 
     bool any = false; 
     bool all = true; 

     for (int i = 0; i < heads.Count; ++i) 
     { 
      bool hasNext = false; 

      if(heads[i] != null) hasNext = heads[i].MoveNext(); 

      if (!hasNext) heads[i] = null; 

      any |= hasNext; 
      all &= hasNext; 
     } 

     if (any && !all && !fillDefault) 
      throw new InvalidOperationException("Input sequences are of different length"); 

     return any; 
    } 
} 
Cuestiones relacionadas