How to compare an element in a list to the others (here, in C#)?

246 Views Asked by At

How is it possible (in my case in C#) to compare an element in a list to all other elements in the list, but (of course) NOT to itself - and to do this for all elements?

Example:

List <sometype>  A = new List<sometype> ();


Foreach (sometype e_1 in A)
{
    Foreach (sometype e_2 in A)
    {
       // compare e_2 to the other elements in A except e_1
    }
}

That means that I must exclude 'e_1' in the 2nd loop, but how can I do this? Whe I use

 Foreach (sometype e_2 in A.Skip() )
in the 2nd loop I hav to know the index of 'e_1'. Wehre I can find this easyly? Or is there another way?

Thx a lot :-)

3

There are 3 best solutions below

1
Rover On

Stupid solution: use for by i and for by j where i != j

If you need just unique items, use HashSet, hashSet.Add will return false if it already have the item.

0
Dmitry Bychenko On

As an easy way out, you can turn foreach into for:

for (int i = 0; i < A.Count; ++i) {
  var e_1 = A[i];

  for (int j = 0; j < A.Count; ++j) {
    // We don't compare item with itself
    if (i == j)
      continue;

    var e_2 = A[j];

    // compare e_2 to the other elements in A except e_1
  }
}

If you insist on foreach (say, you have A being LinkedList<T>, not List<T>) and you don't want to cache the enumeration in the collection (which means, that you are ready to enumerate several times) you can do the same trick with a little help of Linq:

using System.Linq;

foreach (var (e_1, i) in A.Select((item, index) => (item, index))) 
  foreach (var (e_2, j) in A.Select((item, index) => (item, index)))
    if (i != j) {
      // compare e_2 to the other elements in A except e_1
    }
0
flackoverstow On

If you want to persist with foreach loops you could just skip in the inner loop if you detect that the two objects you want to compare live at the same memory location:

        foreach (var e_1 in A)
        {
            foreach (var e_2 in A)
            {
                if(Object.ReferenceEquals(e_1, e_2)) continue; //if the objects have the same memory address, skip
                   
                // compare e_2 to the other elements in A except e_1
                Console.WriteLine($"{e_1} compared to {e_2}");
            }
        }

Using Object.ReferenceEquals will not perform any unnecessarily longer checks that == might perform; it just queries whether the two arguments refer to the same object in memory. See it in action here:

https://dotnetfiddle.net/AaQBKH

This is subtly different to ==, which may perform a more involved comparison, and declare two objects to be equal when they're actually different. You can see this in action in the following example, where the list is a bunch of ValueTuple objects ("a",1), ("a",1), ("b",1) - there are two different ("a",1) with the same content:

https://dotnetfiddle.net/0XNSQM

If you used ReferenceEquals then you would see the code reach the point where it prints the comparison message for the case where the first ("a",1) is compared to the second ("a",1), but because == performs the more in-depth comparison of looking at the data content of each member in a ValueTuple, == will pronounce the two ("a",1) to be equivalent, even though the second one is not the "itself" of the first one etc

Think carefully about what "itself" means to you, and choose your Equals/ReferenceEquals/== appropriately