Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default comparer when using OrderBy extension

Tags:

c#

compare

Out of curiosity: What comparer is used when sorting a bunch of objects using the following extension method?

OrderBy(x=> x)

Background: I have to check wether two ISet< T > instances contain the same elements and considered to use the

bool setsEqual = MySet.SequenceEqual(OtherSet);

method. As the order of those elements contained in the sets are not defined and may differ, a SequenceEqual would fail in those cases where the internal order is not the same. So i would have to explictly define an order. As the order algo for itself is completely irrelevant as long as it´s stable, i just used an "Identity" lambda expression:

bool setsEqual = MySet.OrderBy(x => x).SequenceEqual(OtherSet.OrderBy(x => x);

But what does "Compare the objects themselves" mean to the code? As this OrderBy extension method is a generic one, there must be a default compare algo in place that is able to sort objects without knowing anything more about it, and that would mean a comparison for sorting had to be delegated to the type of the set elements itself. Is there an interface that the elements´ type would have to support, or is there a default comparer (may be comparing internal memory addresses of objects) in place?

like image 995
Udontknow Avatar asked Oct 31 '22 04:10

Udontknow


2 Answers

To answer the question of sorting: sorting uses IComparable<T> or IComperable if that isn't implemented. The IComperable interfaces force you to implement a int CompareTo(object) method (or int CompareTo(T) method if you used the typed version).

The order of your elements is determined by the sign of the int. The value returned is interpreted as follows:

  • 0: the two objects are equivalent (i.e. the same)
  • -1: the compared object precedes this object (i.e. comes before this object)
  • 1: the compared object follows this object (i.e. comes after this object)

The actual value is ignored, the sign is all that matters. If you implement your own IComparable interface, you have to choose the semantics for sort order.

Many objects already implement IComparable already, like all your numbers, strings, etc. You'll need to implement it explicitly if you need to sort objects you've created yourself. It's not a bad practice if you intend those objects to be displayed in a list on screen at all.

As to your specific case, where you just need to determine if a set and another IEnumerable are equivalent, then you would use the ISet<T>.SetEquals(IEnumerable<T>) method which is implemented in the standard library set implementations. Sets, by definition, only guarantee the values are unique, so as long as the number of elements are the same, you only need to detect that all the elements in one IEnumerable can be found in the set.

like image 152
Berin Loritsch Avatar answered Nov 15 '22 05:11

Berin Loritsch


The method used the IComparable<T>-or the IComparable-interface depending on which of both are implemented. If none is implemented the order is arbitrary.

However you won´t need to order you instances before comparing the sets. Simply loop one set and check if all of its elements are contained in the other set. Or use this:

var areEqual = firstSet.All(x => secondSet.Contains(x)) && secondSet.All(x => firstSet.Contains(x));

Or even simpler:

var areEqual = !firstSet.Except(secondSet).Any() && !secondSet.Except(firstSet).Any();

Both ways perform much faster than your appraoch as the iteration of elements stops when the first element is found that does not fit. Using OrderBy you´d loop all elements, regardless if there was already a mismatch.

like image 20
MakePeaceGreatAgain Avatar answered Nov 15 '22 05:11

MakePeaceGreatAgain