Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate over multiple lists

Tags:

c#

foreach

Given a bunch of lists, I need to iterate over them simultaneously. Suppose I have three of them: list1, list2, and list3.

What I found so far is the following:

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
}

This works fine and is quite readable, unless the number of lists is not big. I know how to extend it further to 4, 5,.... lists, but if I zip 10 of them, the code would be extremely long. Is there any possibility to refactor it? Or would I need other solution than Zip function?

like image 252
katta Avatar asked Dec 22 '15 11:12

katta


2 Answers

With a help of a bit of code generation (think T4), one could produce up to 6 overloads (because Tuple is limited to 7 generic arguments) of something similar to:

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

With this Iterate class, iteration becomes very simple:

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

This can be futher generalized (with a total loss of type safety) to:

public static IEnumerable<object[]> Over(params IEnumerable[] enumerables)
like image 181
Anton Gogolev Avatar answered Sep 19 '22 00:09

Anton Gogolev


Why not good old for loop?

  int n = new int[] {
    list1.Count,
    list2.Count,
    list3.Count,
    // etc.
  }.Min(); // if lists have different number of items

  for (int i = 0; i < n; ++i) {
    var item1 = list1[i]; // if you want an item
    ...
  }
like image 27
Dmitry Bychenko Avatar answered Sep 19 '22 00:09

Dmitry Bychenko