如何在C#中执行Python的zip?

问题描述:

Python的zip功能执行以下操作:如何在C#中执行Python的zip?

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

结果

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

请注意,zip可以接受任意数量的参数,而不仅仅是两个参数,如本例所示。到目前为止,答案都集中在这两个可迭代的案例上,在我看来。 – 2010-03-12 00:42:02

+0

@杰弗里提醒。 – 2010-03-12 12:37:21

如何this

C#4.0 LINQ的新ZIP算

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

名称相同,但操作完全不同。 Linq的Zip()可用于对2个输入序列产生python-zip效果,但与2个以上的序列无关。 – 2014-06-18 21:02:14

解决方案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 
     ); 
    } 
} 

解决方案2:以C#4.0邮编相似,但你可以用它在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

当秒数比第一次短时,它会抛出异常 – 2010-03-11 17:21:40

+6

您忘记了处理您的枚举数。 – 2010-03-11 20:24:13

+0

@Eric感谢您的纠正。我编辑了答案 – 2010-03-11 23:40:22

此外,在Cadenza看看它有所有各种漂亮的实用方法。

具体看一下这里的邮编扩展方法: http://gitorious.org/cadenza/cadenza/blobs/master/src/Cadenza/Cadenza.Collections/Enumerable.cs#line1303

我只是遇到了同样的问题。 .NET库不提供解决方案,所以我自己做了。这是我的解决方案。

Pivot方法作为IEnumerable<IEnumerable<T>>的扩展。 它要求所有序列的元素都是相同类型的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; 
    } 
}