Home > Back-end >  Several nested loops to one
Several nested loops to one

Time:03-18

In computational programs there is often such code as

foreach (var x in xx)
    foreach (var y in yy)
        foreach (var z in zz)
            Calculate(x, y, z);

Can it be simplified to just one loop, like

foreach (var (x, y, z) in F(xx, yy, zz)) Calculate(x, y, z);

For any number of variables, probably having different types?

CodePudding user response:

If you want to deal with arbitrary types, you will have to define a generic method for all each amount of parameters you have - this is the same problem as with the predefined delagates Action, Action<T>, Action<T1,T2>, ...

Hence your code could look like this

public static class Helper
{
   public static IEnumerable<(T1,T2)> CrossJoin<T1,T2>(IEnumerable<T1> input1, IEnumerable<T2> input2)
   {
       return input1.SelectMany(x => input2, (x,y) => (x,y));
   }
    
   public static IEnumerable<(T1,T2,T3)> CrossJoin<T1,T2,T3>(IEnumerable<T1> input1, IEnumerable<T2> input2, IEnumerable<T3> input3)
   {
       return input1.SelectMany(x => input2, (x,y) => (x,y))
                    .SelectMany(x => input3, (x,y) => (x.Item1, x.Item2, y));
   }

   // and so on
}

Because we have to define a method for every amount of parameters, there is no need for a sophisticated recursive method which catches all cases. Because only value tuples are used and no arrays are created, the garbage collection won't have so much work as in your solution.

Online demo: https://dotnetfiddle.net/cQwXa5

CodePudding user response:

I have come up with a simple cross join method, but all variables should have the same type T:

public static IEnumerable<T[]> CrossJoin<T>(params IEnumerable<T>[] seqs)
{
    if (seqs.Length == 1) foreach (var x in seqs[0]) yield return new[] { x };
    else
    {
        var subres = CrossJoin(seqs.Skip(1).ToArray());
        var res = from x in seqs[0] from xx in subres select xx.Prepend(x);
        foreach (var x in res) yield return x.ToArray();
    }
}

usage:

foreach (var (x, y, z) in Helper.CrossJoin(xx, yy, zz)) Calculate(x, y, z);

It can be changed to work with object but it will require type casting to use the variables..

  •  Tags:  
  • c#
  • Related