Majak
Majak

Reputation: 1633

C# iterate over two lists - exchangable inner / outer loop

I need to iterate over three lists and process each combination. Order of the most outer and second level loop (list1 / list2) depends on some ordering rules. Moreover I have some logic before and after the last (list3) foreach loop. ProcesPair method uses all three items and depends on their order.

        if (order == Order.Right)
        {
            foreach (var a in list1)
            {
                foreach (var b in list2)
                {
                    DoSomethingBefore();

                    foreach (var c in list3)
                    {
                        ProcessPair(a, b, c);
                    }

                    DoSomethingAfter();
                }
            }
        }
        else if (order == Order.Down)
        {
            foreach (var b in list2)
            {
                foreach (var a in list1)
                {
                    DoSomethingBefore();

                    foreach (var c in list3)
                    {
                        ProcessPair(a, b, c);
                    }

                    DoSomethingAfter();
                }
            }
        }

Is it possible to make it somehow more elegant? I meen, how to reduce loops in code, something like Zip function but each with each other.

Upvotes: 1

Views: 394

Answers (2)

Slai
Slai

Reputation: 22866

Or just refactor the repeating code into a separate method:

void ProcessPairs(List<int> list1, List<int> list2, List<int> list3)
{
    foreach (var a in list1)
        foreach (var b in list2)
        {
            DoSomethingBefore();

            foreach (var c in list3)
                ProcessPair(a, b, c);

            DoSomethingAfter();
        }        
}

and then

    if (order == Order.Right)
        ProcessPairs(list1, list2, list3);
    else if (order == Order.Down)
        ProcessPairs(list2, list1, list3);

Upvotes: 1

Ivan Stoev
Ivan Stoev

Reputation: 205569

Nested loops are indicator for LINQ SelectMany. Hence the equivalent of the sample code could be like this:

var pairs = 
    order == Order.Right ? list1.SelectMany(a => list2, (a, b) => new { a, b }) ?
    order == Order.Down ? list2.SelectMany(b => list1, (b, a) => new { a, b }) :
    null;

if (pairs != null)
{
    foreach (var pair in pairs)
    {
        DoSomethingBefore();
        foreach (var c in list3)
        {
            ProcessPair(pair.a, pair.b, c);
        }
        DoSomethingAfter();
    }
}

Upvotes: 2

Related Questions