Default comparer when using OrderBy extension - c#

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?

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.

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.

Unlike for equality, there's no 'default' comparer for objects in general.
It seems that Comparer<TKey>.Default always returns a comparer, for any type TKey. If no sensible comparison method can be determined, you get an exception, but only once the comparer is used.
At least one object must implement IComparable.

Related

Can two arrays which contain the same elements not be equal?

I encountered a stunning problem today where I'm trying to find if an object is contained in an List collection. The problem is that the list doesn't find the object and returns index as -1 when I can see it right there already. I then created a custom Index Finder to look for the object by comparing the properties rather than a direct equality where I discovered that one of the object's properties, a ushort array which was identical was returning false when compared, but they contain exactly the same element.
The array is as follows:
{ushort[1]} [0]13
and they're exactly the same in both except that one of the object is contained in a List while the other one is on it's own. What could be the cause of this problem? I've tried all types of different ways to get around the problem but I can't just figure out what the problem is. In this particular case what is causing the comparison between the two arrays to return false, I've tied using Object.equals as well as the normal == comparer. Thanks
For arrays, Equals will return true only if you compare two references that point to the same array. To compare different arrays by content, you can use:
Enumerable.SequenceEqual(a1, a2)
Also, if collection contains objects of your custom type, make sure that these types override Equals, equality operator(==) and GetHashCode.

Why Find methods are absent in Enumerable<> while present in List<>?

I think my question says it all. Why Find methods are absent in Enumerable<> while present in List<>. If they were there it would have reduced the burden of writing large LINQ Queries to find something from Enumerable<>. I know i can change the Enumerable to List using .ToList() but that would be a hack.
The Enumerable.FirstOrDefault<TSource> Extension Method does exactly the same as the List<T>.Find Method.
 
Enumerable.FirstOrDefault<TSource> Method
Returns the first element of the sequence that satisfies a condition or a default value if no such element is found.
Return Value: default(TSource) if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate.
 
List<T>.Find Method
Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List<T>.
Return Value: The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type T.
It's very common for classes to include more "helper functions" than interfaces, for the simple reason that adding a helper function to a class simply entails adding code the code for that method to one place (the class in question), while adding a helper function to an interface compels every implementation of that interface to add code for that function.
It would be helpful if the next version of the CLR could provide a means by which interfaces could specify default implementations for their members, especially if implementations of old versions of an interface could be regarded as implementing new versions, using the default implementation for any new members. If such a thing were legal, IEnumerable<T> could add a Count method, which could be overridden by any implementation which was able to determine the number of items without having to iterate through them, but which would otherwise use a default method that would count via iteration. If such a feature existed, adding members like Find to IEnumerable<T> would be useful. Unfortunately, I know of no plan to implement such a feature.

CollectionAssert.AreEqual Failing

I am trying to compare two Lists using
CollectionAssert.AreEqual(ListExpected, ListActual);
But I am getting an exception
Expected and actual are both <System.Collections.Generic.List`1[API.Program.Relation]> with 11 elements
Values differ at index [0]
Expected: <API.Program.Relation>
But was: <API.Program.Relation>
But when I compared the zero element using Assert.AreEqual on field by field everything was fine.
Any idea why I cannot compare using CollectionAssert
An object is "declared" equal to another object in .NET is if its Equals(object other) method returns true. You need to implement that method for your API.Program.Relation class, otherwise .NET considers your objects different unless they are reference-equal. The fact that all fields are the same does not matter to .NET: if you need field-by-field equality semantics, you need to provide an implementation of Equals that supports it.
When you override Equals, don't forget to override GetHashCode as well - these must be overriden together.
If you do not want to or cannot override Equals for some reason, you could use an overload of CollectionAssert.AreEqual that takes an instance of IComparer to assist in comparing collection elements.

C# Generics, Comparing 2 strings fail unless explicitly specified

I thought i've seen it all but this... :)
I was working on a generic graph of type string,
Graph<string> graph = new Graph<string>();
Graph is declared with a class constraint like this:
public class Graph<T> where T : class
Next i fill up the graph with some dynamicly generated strings:
for (char t = 'A'; t < 'J'; t++)
{
GraphPrim.Add(t.ToString());
}
So far so good, (Node is a internal class containing the original value and a list of references to other nodes (because its a graph))
Now, when i try to create relations between the different nodes, i have to look up the right node by checking its value and thats where the weirdness starts.
The following code, is a direct copy of the result found in the immidiate window after doing some tests:
Nodes.First().Value
"A"
Nodes.First().Value == "A"
false
Nodes.First().Value.ToString() == "A"
true
Am i totally missing something or shouldn't Nodes.First().Value == "A" use a string comparison method. (The JIT compiler has knowledge about the type beeing used on runtime, and with that, its supported methods, right?). It seems to me like when not explicitly specifying a string, it will do a reference check rather then a string test.
It would be great if someone could explain this to me,
Thanks in advance!
If the types aren't fully known up front (i.e. Value is only known as T, and is not strictly known to be a string), use things like:
object.Equals(Nodes.First().Value,"A")
Of course, you could cast, but in this case you'd need a double-cast ((string)(object)) which is ugly.
If you know the two objects are the same type (i.e. two T values), then you can use:
EqualityComparer<T>.Default.Equals(x,y)
The advantage of the above is that it avoids boxing of structs and supports lifted Nullable<T> operators, and IEquatable<T> in addition to Equals.
If the Value property of your Nodes is object, the == operator in
Nodes.First().Value == "A"
will do a comparison by reference instead of comparing strings.
== is a static method and therefore not virtual. The selection of which == method to use is done at compile-time, not run-time. Depending on the compile-time type of the object, it is probably choosing the implementation of == for objects that compares by reference.
If you use the virtual Equals methods instead, this will work as you expect.

list sorting in c#

i have list of objects i need to sort the list based on object's property1 and i need to sort again the resultant list with object's property2 without loosing the grouping done in first sorting ....
for ex:
obj has 2 property name and location
i need to have a final list of objects which has been sorted with region and objects of same region should be sorted by name...
(Assuming you don't have LINQ available to you, which makes this trivial.)
If you look in MiscUtil, you'll find two useful classes: ProjectionComparer and LinkedComparer (IIRC).
ProjectionComparer basically implements the LINQ "order by" concept - you specify how to convert a source element to a key value, and the comparer will order by those key values.
LinkedComparer takes two comparers and returns a new comparer which uses the "primary" comparer first, and the "secondary" comparer if values are equal with respect to the primary one.
Create two projection comparers (one for each property) and then a linked comparer with the two of them, then pass that to List<T>.Sort. Let me know if you need a full code sample, but it would be something like (using C# 3):
var comparer = new LinkedComparer<Foo>
(ProjectionComparer<Foo>.Create(x => x.FirstProperty),
ProjectionComparer<Foo>.Create(x => x.SecondProperty));
(In C# 2 you could use anonymous methods, they'd just be a bit more long-winded.)
Sounds like you want to use LINQ's orderby and thenby syntax.
A List has a Sort method which takes a Comparision delegate as an argument.
There are also overloads where you can pass in your own comparer.
So, you can write a class which implements IComparer. Then, in the implementation of this class, you write the code where you compare the 2 objects on the properties you want.

Categories

Resources