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

C# 压缩C中可枚举的多个/任意数,c#,linq,C#,Linq,在Linq中,我们可以使用以下方法将两个列表组合起来: 我希望等效于压缩任意数量的相同类型的枚举。方法签名有点像这样: public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner) IEnumerator<T>[

在Linq中,我们可以使用以下方法将两个列表组合起来:

我希望等效于压缩任意数量的相同类型的枚举。方法签名有点像这样:

public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner)
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;
}
当作为可枚举项进行迭代时,它返回一个可枚举项,其中包含来自每个相应可枚举项的元素


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

因为输入是一个数组,所以您可以创建一个IEnumerator[] 然后给他们每个人打电话。大概是这样的:

public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner)
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;
}

由于输入是数组,因此可以创建IEnumerator[] 然后给他们每个人打电话。大概是这样的:

public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner)
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;
}
那么

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

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

应该是相当简单的建设。可以在上找到双元素Zip的参考实现;推广到n个元素应该不难。我已经在自己身上实现了,如果我没有得到任何答案,我会把它作为一个答案发布,但是,我很想知道它是否已经存在,或者是否有比我更好的实现。据我所知,框架中没有任何东西,我很惊讶没有找到一个实现,“不使用谷歌,也不使用谷歌。”海因茨:是的,我已经做了大量的搜索应该是相当简单的建设。可以在上找到双元素Zip的参考实现;推广到n个元素应该不难。我已经在自己身上实现了,如果我没有得到任何答案,我会把它作为一个答案发布,但是,我很想知道它是否已经存在,或者是否有比我更好的实现。据我所知,框架中没有任何东西,我很惊讶没有找到一个实现,“不使用谷歌,也不使用谷歌。”海因茨:是的,我已经做了大量的搜索啊,是的,我不应该在那个签名中发布数组,但是你已经给出了一个与我已经得到的非常相似的答案,参数Func对我来说有点奇怪。我想说的是Func combinerI,我想用Zip组合一对列表的方式来组合所有列表。Zip中的结果选择器有两个参数。经过检查,我的答案与您的答案非常相似,但有些不同。希望这意味着我们在正确的直线上+1。啊,是的,我不应该在那个签名中发布数组,但是你得到了一个与我已经得到的非常相似的答案。参数Func对我来说有点奇怪。我想说的是Func combinerI,我想用Zip组合一对列表的方式来组合所有列表。Zip中的结果选择器有两个参数。经过检查,我的答案与您的答案非常相似,但有些不同。希望这意味着我们的思路是正确的+1。IEnumerator是IDisposable的,但这段代码从不调用Dispose@ta.speot.is已修复。IEnumerator可IDisposable,但此代码从不调用Dispose@ta.speot.是固定的。