Search code examples
c#mathematical-optimization

Iterating over unordered pairs of elements stored in a collection


In C#, I have got a collection of unique elements and I want to efficeiently execute some code for each unordered pair. For instance, if my container holds {a,b,c}, the unordered pairs are (a,b), (a,c) and (b,c). The problem arises in the scope of performing a 2-opt optimization, thus efficency is an issue.

  • My current solution looks like:

    foreach(var a in container) 
    {
        foreach(var b in container)
        {
            if (a < b)
            {
                 // execute code    
            }
        }
     }
    

    Obviously, this can be modified easily if the operator [] is available to get the i-th element (i.e. if the underlying data structure is a list.) But for all other containers, the solution is dependent on the existence of some comparison function and not very efficient.

  • I've also tried a formulation based on a LINQ statement that generates each desired pair exactly once. However, as expected, this was much slower than the first approach. This applies to a solution using ElementAt too.

Edit: here is the (improved) LINQ code that was used:

var x = from a in container
        from b in container
        where a < b 
        select new KeyValuePair<int,int>(a,b);

Still, execution is slower by a factor of 3-5 compared to the other solutions.

  • Here is the way I would do it in C++ (obtaining good efficiency):

    for(auto it1 = container.begin(); it1!=container.end(); ++it1) 
    {
        auto it2 = it1;
        for(++it2; it2!=container.end(); ++it2) 
        {
            // execute code    
        }
     }
    

    Unfortunatelly, to transform this into C#, it would be required to clone the (internally used) Enumerator, which is not supported by the language itself.

Has anyone a better idea / solution?


Solution

  • Did you try to copy the elements into a list first and then do the algorithm with the indexer ([i]) operator? Since the algorithm has quadratic runtime anyways it may be negligible to have a linear copy operation in front of it. You would have to find out the actual runtime for small, middle and large containers yourself...

    I think it may be worth a try, this may well be a lot faster than working with the comparison operator each time.

    You could also check if the container is of type IList<T> and jump past the copy operation.