代码之家  ›  专栏  ›  技术社区  ›  Erik Forbes

如何将两个IEnumerables合并(或压缩)在一起?

  •  6
  • Erik Forbes  · 技术社区  · 16 年前

    IEnumerable<T> IEnumerable<U> IEnumerable<KeyValuePair<T,U>> 其中KeyValuePair中连接在一起的元素的索引相同。注意,我没有使用IList,因此我没有要合并的项的计数或索引。我怎样才能最好地做到这一点?我更喜欢LINQ的答案,但任何能以优雅的方式完成工作的方法都会奏效。

    10 回复  |  直到 13 年前
        1
  •  17
  •   Erik Forbes    10 年前

    注: 从.NET4.0开始,该框架包括 .Zip IEnumerable上的扩展方法,已记录 here . 以下内容是为后代保留的,并用于.NET framework 4.0之前的版本。

    // From http://community.bartdesmet.net/blogs/bart/archive/2008/11/03/c-4-0-feature-focus-part-3-intermezzo-linq-s-new-zip-operator.aspx
    public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> func) {
        if (first == null) 
            throw new ArgumentNullException("first");
        if (second == null) 
            throw new ArgumentNullException("second");
        if (func == null)
            throw new ArgumentNullException("func");
        using (var ie1 = first.GetEnumerator())
        using (var ie2 = second.GetEnumerator())
            while (ie1.MoveNext() && ie2.MoveNext())
                yield return func(ie1.Current, ie2.Current);
    }
    
    public static IEnumerable<KeyValuePair<T, R>> Zip<T, R>(this IEnumerable<T> first, IEnumerable<R> second) {
        return first.Zip(second, (f, s) => new KeyValuePair<T, R>(f, s));
    }
    

    编辑 :在评论之后,我必须澄清并解决一些问题:

    • 我最初从 Bart De Smet's blog
    • 添加了枚举器(这也是 noted 关于巴特的原始帖子)
    • 增加了空参数检查(也在Bart的帖子中讨论)
        2
  •  17
  •   ProgrammingLlama Raveena Sarda    3 年前

    int[] numbers = { 1, 2, 3, 4 };
    string[] words = { "one", "two", "three" };
    
    var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
    

    Documentation :

    该方法将第一个序列的每个元素与第二个序列中具有相同索引的元素合并。如果序列的元素数不相同,则该方法将合并序列,直到到达其中一个序列的末尾。例如,如果一个序列有三个元素,而另一个序列有四个元素,则结果序列将只有三个元素。

        3
  •  1
  •   Welbog    16 年前

    仔细想想你在这里提出的问题:

    您希望合并两个IEnumerables,其中 索引 在KeyValuePair中连接在一起的元素中有个是相同的“,但您” 指数 对于我正在合并的项目”。

    无法保证您的IEnumerables已排序或未排序。你的两个IEnumerable对象之间没有关联,那么你怎么能期望将它们关联起来呢?

        4
  •  1
  •   Community CDub    4 年前

    看看 nextension :

    目前实施的方法

    数不清

    • ForEach对IEnumerable的每个元素执行指定的操作。
    • 将项目分组为相同大小的批次。
    • 至少检查IEnumerable中至少有一定数量的项。
    • AtMost检查IEnumerable中的项不超过一定数量。
    • 拉链
    • 循环通过重复另一个列表来创建列表。
        5
  •  1
  •   Reed Copsey    16 年前

    IEnumerable<KeyValuePair<T,U>> Merge<T,U>(IEnumerable<T> keyCollection, IEnumerable<U> valueCollection)
    {
        var keys = keyCollection.GetEnumerator();
        var values = valueCollection.GetEnumerator();
        try
        { 
            keys.Reset();
            values.Reset();
    
            while (keys.MoveNext() && values.MoveNext())
            {
                yield return new KeyValuePair<T,U>(keys.Current,values.Current);
            }
        }
        finally
        {
            keys.Dispose();
            values.Dispose();
        }
    }
    

    这应该可以正常工作,并在之后正确清理。

        6
  •  0
  •   erikkallen    16 年前

    IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> t, IEnumerable<U> u) {
        IEnumerator<T> et = t.GetEnumerator();
        IEnumerator<U> eu = u.GetEnumerator();
    
        for (;;) {
            bool bt = et.MoveNext();
            bool bu = eu.MoveNext();
            if (bt != bu)
                throw new ArgumentException("Different number of elements in t and u");
            if (!bt)
                break;
            yield return new KeyValuePair<T, U>(et.Current, eu.Current);
        }
    }
    
        7
  •  0
  •   Jeff Yates    16 年前

    你可以使用 Zip 方法 MoreLINQ .

        8
  •  0
  •   Daniel Brückner    16 年前

    MSDN具有以下功能 Custom Sequence Operators 实例韦尔博格是对的;如果您对基础数据没有索引,则无法保证该操作执行您所检查的操作。

        9
  •  0
  •   Mauricio Scheffer    16 年前

    来自 functional-dotnet project 亚历克赛·罗曼诺夫:

    /// <summary>
    /// Takes two sequences and returns a sequence of corresponding pairs. 
    /// If one sequence is short, excess elements of the longer sequence are discarded.
    /// </summary>
    /// <typeparam name="T1">The type of the 1.</typeparam>
    /// <typeparam name="T2">The type of the 2.</typeparam>
    /// <param name="sequence1">The first sequence.</param>
    /// <param name="sequence2">The second sequence.</param>
    /// <returns></returns>
    public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(
        this IEnumerable<T1> sequence1, IEnumerable<T2> sequence2) {
        using (
            IEnumerator<T1> enumerator1 = sequence1.GetEnumerator())
        using (
            IEnumerator<T2> enumerator2 = sequence2.GetEnumerator()) {
            while (enumerator1.MoveNext() && enumerator2.MoveNext()) {
                yield return
                    Pair.New(enumerator1.Current, enumerator2.Current);
            }
        }
        //
        //zip :: [a] -> [b] -> [(a,b)]
        //zip (a:as) (b:bs) = (a,b) : zip as bs
        //zip _      _      = []
    }
    

    代替 Pair.New KeyValuePair<T1, T2> (和返回类型)并且您可以继续。

        10
  •  0
  •   Community CDub    7 年前

    JaredPar 有一个 library Zip 这将启用您想要执行的操作。