在C#中压缩多个/任意数量的枚举数

时间:2014-06-12 09:52:52

标签: c# linq

在Linq中,我们可以使用Enumerable.Zip方法组合两个列表:

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> resultSelector
)

我希望相当于Zip任意数量的相同类型的枚举。方法签名的东西有点像这样:

public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner)

当枚举为枚举时,它返回一个包含每个相应可枚举元素的枚举。

这是否存在于任何地方?或者使用现有的Linq方法构建是否简单?聚合多个拉链?

2 个答案:

答案 0 :(得分:3)

由于输入是一个数组,您可以创建一个IEnumerator<TIn>[] 然后在每个上面调用MoveNext。像这样:

IEnumerator<T>[] enumerators = inputs.Select(inp => inp.GetEnumerator()).ToArray();
int len = enumerators.Length;
while (true) {
    TResult[] result = new TResult[len];
    for(int i = 0; i < len; ++i) {
        if (!enumerators[i].MoveNext()) yield break;
        result[i] = resultSelector(enumerators[i].Current);
    }
    yield return result;
}

答案 1 :(得分:1)

怎么样,

using System;
using System.Collections.Generic;
using System.Linq;

...

public static IEnumerable<TResult> Zip<T, TResult>(
        this IEnumerable<T> source,
        Func<IList<T>, TResult> resultSelector,
        params IEnumerable<T>[] others)
{
    if (resultSelector == null)
    {
        throw new ArgumentNullException("resultSelector");
    }

    var enumerators = new List<IEnumerator<T>>(others.Length + 1);
    enumerators.Add(source.GetEnumerator());
    enumerators.AddRange(others.Select(e => e.GetEnumerator()));

    try
    {
        var buffer = new T[enumerators.Count];
        while (true)
        {
            for (var i = 0; i < enumerators.Count; i++)
            {
                if (!enumerators[i].MoveNext())
                {
                    yield break;
                }

                buffer[i] = enumerators[i].Current;
            }

            yield return resultSelector(buffer);
        }
    }
    finally
    {
        foreach (var enumerator in enumerators)
        {
            enumerator.Dispose();
        }
    }
}