Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# IEnumerable double iteration

Tags:

c#

ienumerable

This is out of curiosity I want to ask this question...

Here is my code:

for (int i = 0; i < myList.Count - 1; ++i)
{
    for (int j = i+1; j < myList.Count; ++j)
    {
        DoMyStuff(myList[i], myList[j]);
    }
}

Pretty simple loop, but obviously it only works with List... But I was wondering... how can I code this loop in order to make it independent of the collection's type (deriving from IEnumerable...) My first thought:

IEnumerator it1 = myList.GetEnumerator();
while (it1.MoveNext())
{
    IEnumerator it2 = it1; // this part is obviously wrong
    while (it2.MoveNext())
    {
        DoMyStuff(it1.Current, it2.Current);
    }
}
like image 547
s0ubap Avatar asked Dec 04 '12 13:12

s0ubap


1 Answers

Because enumerators don't have an efficient way of getting the n'th element, your best bet is to copy the enumerable into a list, then use your existing code:

void CrossMap<T>(IEnumerable<T> enumerable)
{
    List<T> myList = enumerable.ToList();

    for (int i = 0; i < myList.Count - 1; ++i)
    {
        for (int j = i+1; j < myList.Count; ++j)
        {
            DoMyStuff(myList[i], myList[j]);
        }
    }
}

However, there is a rather tricksie hack you can do with some collection types. Because the enumerators of some of the collection types in the BCL are declared as value types, rather than reference types, you can create an implicit clone of the state of an enumerator by copying it to another variable:

// notice the struct constraint!
void CrossMap<TEnum, T>(TEnum enumerator) where TEnum : struct, IEnumerator<T>
{
    while (enumerator.MoveNext())
    {
        TEnum enum2 = enumerator;    // value type, so this makes an implicit clone!
        while (enum2.MoveNext())
        {
            DoMyStuff(enumerator.Current, enum2.Current);
        }
    }
}

// to use (you have to specify the type args exactly)
List<int> list = Enumerable.Range(0, 10).ToList();
CrossMap<List<int>.Enumerator, int>(list.GetEnumerator());

This is quite obtuse, and quite hard to use, so you should only do this if this is performance and space-critical.

like image 58
thecoop Avatar answered Sep 29 '22 23:09

thecoop