How do I merge (or zip) two IEnumerables together?

前端 未结 10 1572
予麋鹿
予麋鹿 2020-12-17 00:38

I have an IEnumerable and an IEnumerable that I want merged into an IEnumerable> where

相关标签:
10条回答
  • 2020-12-17 00:46

    Untested, but should work:

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-17 00:47

    I would use something along the lines of -

    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();
        }
    }
    

    This should work correctly, and cleanup properly afterwards.

    0 讨论(0)
  • 2020-12-17 00:51

    Note: As of .NET 4.0, the framework includes a .Zip extension method on IEnumerable, documented here. The following is maintained for posterity and for use in .NET framework version earlier than 4.0.

    I use these extension methods:

    // 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));
    }
    

    EDIT: after the comments I'm obliged to clarify and fix some things:

    • I originally took the first Zip implementation verbatim from Bart De Smet's blog
    • Added enumerator disposing (which was also noted on Bart's original post)
    • Added null parameter checking (also discussed in Bart's post)
    0 讨论(0)
  • 2020-12-17 00:51

    The MSDN has the following Custom Sequence Operators example. And Welbog is right; if you have no index on the underlying data you have no guarantee that the operation does what you exspect.

    0 讨论(0)
  • 2020-12-17 00:52

    Think about what you're asking a bit more closely here:

    You want to combine two IEnumerables in which "the indexes of the elements joined together in the KeyValuePair are the same", but you "don't have a count or an index for the items I'm merging".

    There's no guarantee your IEnumerables are even sorted or unsorted. There's no correlation between your two IEnumerable objects, so how can you expect to correlate them?

    0 讨论(0)
  • 2020-12-17 00:56

    Look at nextension:

    Currently Implemented Methods

    IEnumerable

    • ForEach Performs a specified action on each element of the IEnumerable.
    • Clump Groups items into same size lots.
    • Scan Creates a list by applying a delegate to pairs of items in the IEnumerable.
    • AtLeast Checks there are at least a certain amount of items in the IEnumerable.
    • AtMost Checks there are no more than a certain amount of items in the IEnumerable.
    • Zip Creates a list by combining two other lists into one.
    • Cycle Creates a list by repeating another list.
    0 讨论(0)
提交回复
热议问题