动态压缩列表

时间:2019-04-16 02:23:53

标签: c# ienumerable

我看到这样的解决方案,在编译时,zip的已知List数大于两个List

public static class MyFunkyExtensions
{
    public static IEnumerable<TResult> ZipThree<T1, T2, T3, TResult>(
        this IEnumerable<T1> source,
        IEnumerable<T2> second,
        IEnumerable<T3> third,
        Func<T1, T2, T3, TResult> func)
    {
        using (var e1 = source.GetEnumerator())
        using (var e2 = second.GetEnumerator())
        using (var e3 = third.GetEnumerator())
        {
            while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext())
                yield return func(e1.Current, e2.Current, e3.Current);
        }
    }
}

如果您有List<List<>>并且想要动态压缩它们,正确的代码是什么? 请注意,列表数量在编译时未知。我不想创建ZipFour,ZipFive等...

2 个答案:

答案 0 :(得分:1)

像这样吗?

public static IEnumerable<TResult> ZipAll<T, TResult>(
    IEnumerable<IEnumerable<T>> lists,
    Func<IEnumerable<T>, TResult> func)
{
    var enumerators = lists.Select(l => l.GetEnumerator()).ToArray();
    while(enumerators.All(e => e.MoveNext()))
    {   
        yield return func(enumerators.Select(e => e.Current));
    }

    foreach (var enumerator in enumerators)
    {
        enumerator.Dispose();
    }
}

这假设每个列表/枚举的类型参数都是相同的(即,您想在类似List<List<int>>的名称上调用它。如果不是这样,则需要使用非泛型{{而是使用1}}(并结束IEnumerable,因为非通用foreach不是一次性的)。

我没有对此进行大量测试;有兴趣了解评论者可能会戳出什么样的漏洞。

编辑:

  • 正如MineR所指出的那样,此实现未捕获示例实现中IEnumerable语句的影响。您可以通过几种不同的方式来修改它以使用一次try / finally(或多次try / finally),具体取决于您希望如何处理usingGetEnumerator,{ {1}}和MoveNext
  • 此外,尽管您可以压缩无限长的枚举,但Current从概念上讲需要有限数量的枚举。如果Dispose的类型为Zip,可能会更正确。如果lists是无限的,则将抛出ICollection<IEnumerable<T>>异常。
  • 经过一番讨论:一个特定的要求是能够在选择器函数中使用索引器。这可以通过以下方式实现:将第三个参数设为OutOfMemory而不是lists,并向Func<IList<T>, TResult>添加Func<IEnumerable<T>, TResult>

答案 1 :(得分:0)

在不确切知道要如何压缩列表的情况下,很难编写确切的解决方案,但是您可以执行以下操作:

List<int> ListOne = new List<int> { 1, 2, 3, 4, 5 };
List<int> ListTwo = new List<int> { 123, 12, 3243, 223 };
List<int> ListThree = new List<int> { 23, 23, 23, 23, 23, 23 };

var AllLists = new List<List<int>> { ListOne, ListTwo, ListThree };

var result = AllLists.Aggregate((acc, val) => acc.Zip(val, (init, each) => init + each).ToList());

您传递给Zip函数的函数将是您显然想要处理Zipping的情况,在这种情况下,将ints只是简单地添加在一起,但是可以将字符串连接起来,等等。Aggregate函数将用于枚举所有List并将结果合并到一个容器中,在本例中为列表。