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?
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.