迭代多个列表

时间:2015-12-22 11:54:51

标签: c# foreach

鉴于一堆列表,我需要同时迭代它们。假设我有三个:list1list2list3

到目前为止我发现了以下内容:

foreach (var tuple in list1.Zip(list2, (first, second) => new { object1 = first, object2 = second })
                          .Zip(list3, (first, second) => new { object1 = first.object1, object2 = first.object2, object3 = second }))
{
  //do stuff
}

除非列表数量不大,否则这种方法很好并且可读性很强。我知道如何将它进一步扩展到4,5,....列表,但如果我压缩其中的10个,代码将会非常长。有没有可能重构它?或者我需要其他解决方案而不是Zip函数?

4 个答案:

答案 0 :(得分:8)

借助一些代码生成(想想T4),最多可以产生6次重载(因为Tuple限制为7个通用参数)类似于:

public static class Iterate
{
    public static IEnumerable<Tuple<T1, T2, T3>> Over<T1, T2, T3>(IEnumerable<T1> t1s, IEnumerable<T2> t2s, IEnumerable<T3> t3s)
    {
        using(var it1s = t1s.GetEnumerator())
        using(var it2s = t2s.GetEnumerator())
        using(var it3s = t3s.GetEnumerator())
        {
            while(it1s.MoveNext() && it2s.MoveNext() && it3s.MoveNext())
                yield return Tuple.Create(it1s.Current, it2s.Current, it3s.Current);
        }
    }
}

使用这个Iterate类,迭代变得非常简单:

foreach(var t in Iterate.Over(
    new[] { 1, 2, 3 }, 
    new[] { "a", "b", "c" }, 
    new[] { 1f, 2f, 3f }))
{
}

这可以进一步推广(完全丧失类型安全性):

public static IEnumerable<object[]> Over(params IEnumerable[] enumerables)

答案 1 :(得分:4)

为什么不好老#tawkchat-minified-container { position: fixed; bottom: 0; width: 200px; right: 0;} 循环?

for

答案 2 :(得分:1)

据我所知,真正的问题是要迭代的未知数量的列表。我看到的另一个问题是,不能保证所有列表都具有相同的长度......正确吗?

如果列表的数量未知,元组将不会这样做,因为它们将达到8 ...并且必须在编译时设置...

在这种情况下,我会建议你,而不是映射到一个元组,做一个简单而又非常古老的结构:一个矩阵!宽度将是列表的数量(在运行时已知),深度将是最长的列表。您可以使用一个简单且知名的for进行迭代,让编译器优化内存和分配......代码不仅可以被C#人员阅读,而且对于任何使用任何编程语言的人来说都是如此。

答案 3 :(得分:0)

添加@ AntonGogolev的回答,关于他的最后一句话......如果你不关心类型安全和性能(用于装箱拆箱),你可以使用{{1来实现一个枚举器}}:

object[]

警告:我们没有做任何努力来优化这段代码,而且它已经写完了: - )

您可以像以下一样使用它:

public static class Iterator
{
   public static IEnumerable<object[]> Enumerate(params IEnumerable[] enumerables)
   {
     var list = new List<object>();
     var enumerators = new List<IEnumerator>();
     bool end = false;

     foreach(var enu in enumerables)
     {
       enumerators.Add(enu.GetEnumerator());
     }
     while(!end)
     {
       list.Clear();
       foreach(var enu in enumerators)
       {
           if(!enu.MoveNext()) { end = true; break; }
           list.Add(enu.Current);                  
       }
       if(!end) yield return list.ToArray();           
     }
   }
}

在这里小提琴:https://dotnetfiddle.net/irTY8M