动态压缩列表[重复]

问题描述 投票:2回答:2

这个问题在这里已有答案:

我已经在编译时看到像zip这样的解决方案,已知数量的Lists大于两个Lists:

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等...

c# ienumerable
2个回答
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 / enumerable的类型参数是相同的(即你想在List<List<int>>之类的东西上调用它。如果不是这样的话,你需要使用非泛型的IEnumerable(并且摆脱foreach)最后,因为非通用的IEnumerable不是一次性的)。

我没有对此进行过大量测试;有兴趣看看评论者可能会捅到什么样的洞。

编辑:

  • 正如MineR所呼吁的那样,此实现并未捕获示例实现中using语句的影响。有几种不同的方法可以修改它来使用try / finally(或多个try / finallys),具体取决于你想要如何处理GetEnumeratorMoveNextCurrentDispose中可能发生的异常。
  • 此外,虽然你可以压缩无限长度的可用数据,但Zip在概念上需要有限数量的这些可用数据。如果listsICollection<IEnumerable<T>>类型可能会更正确。如果OutOfMemory是无限的,这将抛出lists异常。
  • 经过一番讨论:一个特定的要求是能够在选择器函数中使用索引器。这可以通过制作第三个参数Func<IList<T>, TResult>而不是Func<IEnumerable<T>, TResult>,并将ToArray()添加到enumerators.Select(e => e.Current)来实现。

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,在这种情况下,int只是简单地加在一起,但是字符串可以连接等.Golregate函数将用于枚举所有列表但组合将结果放入单个容器中,在本例中为List。

© www.soinside.com 2019 - 2024. All rights reserved.