I have several objects that depending on the use case are considered Equal differently.
I need to use these objects as keys for dictionaries and as far as I know Dictionary<> use the Equals() method which limits me to have only one implementation of it.
Is there any workaround to this? I expected to be able to inject a EqualityComparer, a delegate or something so Dictionary<> can use different ways of searching for items.
Thanks.
Any one dictionary can only have a single equality comparer. You can't ask it to find a key with respect to a particular equality comparer, because otherwise its stored hash codes will be useless, and it would have to just do a linear search.
If you have multiple equality comparers you want to search across, I'd keep several separate dictionaries, each with a different comparer.
(If you just wanted to be able to specify the equality comparer and had missed it, that's what the Dictionary(IEqualityComparer<TKey> comparer) constructor is for).
Related
In .NET, Whenever we override Equals() method for a class, it is a normal practice to override the GetHashCode() method as well. Doing so will ensure better performance when the object is used in Hashtables and Dictionaries. Two keys are considered to be equal in Hashtable only if their GetHashCode() values are same. My question is why can't the Hashtables use Equals() method to compare the keys?, that would have removed the burden of overriding GetHashCode() method.
HastTable/Dictionaries use Equals in case of collision (when two hash codes are same).
Why don't they use only Equals ?
Because that would require a lot more processing than accessing/(comparing) integer value value (hash code). (Since hash codes are used as index so they have the complexity of O(1))
A HashSet (or HashTable, or Dictionary) uses an array of buckets to distribute the items, those buckets are indexed by the object's hash code (which should be immutable), so the search of the bucket the item is in is O(1).
Then it uses Equals within that bucket to find the exact match if there's more than one item with the same hashcode: that's O(N) since it needs to iterate over all items within that bucket to find the match.
If a hashset used only Equals, finding an item would be O(N) and you could aswell be using a list, or an array.
That's also why two equal items must have the same hashcode, but two items with the same hashcode don't necessarily need to be equal.
Two object instances that compare as equal must always have identical hash codes. If this doesn't hold, hash-based data structures will not work correctly. It's not a matter of performance.
Two object instances that don't compare as equal should ideally have different hash codes. If this doesn't hold, hash-based data structures will have degraded performance, but at least they'll still work.
Thus, for a given object instance, GetHashCode needs to reflect the logic of Equals, to some extent.
Now if you're overriding the Equals method, you're providing custom comparison logic. As an example, let's say your custom comparison logic involves only one particular data member of the instance. For a non-virtual GetHashCode method to be useful, it would have to be general enough to understand your custom Equals logic and be able to come up with a custom hash code function (one that only involves your chosen data member) on the spot.
It's not that easy to write such a sophisticated GetHashCode and it's not worth the trouble either, when the user can simply provide a custom one-liner that honors the initial requirement.
Alright so I'm taking everything I've learned and trying to implement it in C#. Given that I have a background in Java my ride has been pretty smooth so far, but I'm running into issues into using the Comparer object and functions etc. I don't care about direct implementation/translation, but I want to know how C# compares two generic values. What does it use to sort them? Hashcode, or maybe some C#-specific methodology?
So just to clarify, I know how to sort, search, etc. using methods in C#. What I want to know is what's going on under the hood - what are the Comparer and other functions using to compare two values of generics?
I want to know how C# compares two generic values
It doesn't/can't, that is why there are the ICompariable and IComparer interfaces..
What I want to know is what's going on under the hood
If you're talking about types provided by .Net then..
If you have an array of types (such as string or integer) that already support IComparer, you can sort that array without providing any explicit reference to IComparer. In that case, the elements of the array are cast to the default implementation of IComparer (Comparer.Default) for you.
How to use the IComparable and IComparer interfaces in Visual C# is probably the best article I've seen specific to your question.
The role of IComparable is to provide a method of comparing two objects of a particular type
The role of IComparer is to provide additional comparison mechanisms. For example, you may want to provide ordering of your class on several fields or properties, ascending and descending order on the same field, or both.
I have a dictionary data structure that must be passed around using WCF. To do that I created a member property with get and set methods. I can basicly achieve the same functionality, with this property being either a:
IDictionary<keyType, valueType>
or a
IList<KeyValuePair<keyType, valueType>>
I can see no strong reason for choosing one over the other. One mild reaons I could think of is:
IDictionary - People reading the code will think that IDictionary makes more sense, since the data structure is a dictionary, but in terms of what is passed through WCF they are all the same.
Can anyone think of a reason to choose IList? If there is none I'll just go with IDictionary.
Design your interfaces based on use, not on implementation.
If the consumer of a class needs to iterate through the entire set, use IEnumerable. If they should be able to modify the result, and need index-based access, return IList. If they want specific items, and there is a single useful key value, return IDictionary.
Write your internal code this way, too :)
It depends on your consumers. I would cater for the most likely use case and make their API as simple as possible. Edge cases can always iterate the dictionary via the Values collection.
Don't make them think about it. If the the term dictionary is what they'd think about as the result of the operation and then the type with name is a very useful thing to use.
If the collection of keyValuePairs expects unique key, you can use dictionary.
If the same key can appear in more than one keyValuePair, use Ilist/ ienumerable.
I need a Dictionary whose key is an array of integers for example Dictionary<int[],string> or
Dictionary<List<int>,string>.
But I am quite surprised that the Equality method and hash code method is not defined for me. Is there any easy way to implement such a structure other than creating my own MyType: List<int> and to define all necessary methods?
It isn't predefined because it is expensive. If you know your list is short then just implement the obvious overrides. If not, you'll have to come up with some kind of heuristic for at least GetHashCode. Say, GetHashCode of only the first couple of elements xor-ed together with the Length.
Instead of creating your own type, you could provide two methods somewhere
string ConvertListToString(List<int> l){...};
List<int> ConvertStringToList(string s){...};
and use a Dictionary<string,string> instead.
GetHashCode and Equality are defined for List, they're just not overridden to give you behavior that you might expect and instead.
If you're using .NET 3.5 you can write a extension methods for List that implements an override for both GetHashCode(), and Equality()
I want something along the lines of Python's tuples (or, for sets, frozensets), which are hashable. I have a List<String> which is most certainly not hashing correctly (i.e. by value).
You will have to define your own container, possibly wrapping the List, to get useful semantics for equality-hash-equals (GetHashCode and Equals). You could even make the wrapper conform to IList if you like.
To avoid mutability issues and a changing GetHashCode/Equals results (which would make use of your new object in a hashing Dictionary problematic!) you should also provide some kind of guard (perhaps make a copy of the input upon creation of your type) and/or document the constraints.
You can use SequenceEqual to implement Equals rather trivially, but you'll need to implement a GetHashCode in a relevant way -- a simple method is a shifting XOR of the GetHashCode of each element.
Alternatively, if this is just used in a single Dictionary you can supply a custom IEqualityComparer and avoid creating a wrapped type: Dictionary constructor overload.
It depends what your final goals are and there very well already be such wrapping containers :-)
Note: In .NET4 there is a set of Tuple<...> classes which override GetHashCode and Equals. See cadenza as the 3rd party alternative for prior .NET versions.