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()
Related
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 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).
I'm just curious.. When I call Distinct<>() (from Linq) on HashSet, does .NET know, that this IEnumerable always contains distinct set of values, and optimizes this call away?
Judging by looking at the code through Reflector, I would have to say no.
The code ends up construct an instance of an iterator method generated class regardless of what type you give it.
This problem is also compounded by the fact that you can specify comparer objects for both the Hashset and the Distinct method, which means the optimization would only be used in very few cases.
For instance, in the following case it could actually optimize the call away, but it wouldn't be able to know that:
var set = new HashSet<int>(new MyOwnInt32Comparer());
var distinct = set.Distinct(new MyOwnInt32Comparer());
Since I give it two instances of the comparer class, and such classes usually doesn't implement equality methods, the Distinct method would have no way of knowing that the two comparer implementations are actually identical.
In any case, this is a case where the programmer knows more about the code than the runtime, so take advantage of it. Linq may be very good but it's not omnipotent, so use your knowledge to your advantage.
I think No, because the input of Enumerable class for distinct method is IEnumerable and there is nothing specific for determining it's a hash set (so do not do anything).
No, looking at the implementation in reflector, it doesn't check if the enumeration is a HashSet<T>. The underlying iterator creates a new set and fills it during enumeration, so the overhead shouldn't be that large though.
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.
I have a mutable class that I'm using as a key to a generic dictionary. Two keys should be equal only if their references are equal.
From what I've read, in this case, I don't need to override Equals, GetHashCode , or implement IEqualityComparer.
Is this correct?
Yes. The default comparison operation in System.Object uses reference equality. If this behavior is what you want, the defaults should work fine.
Yes, this is correct. As long as you don't override, reference is the default comparison.
I'll add on to what everyone else has said here (yes) but with one more point that no one seems to have mentioned here.
When using generic collections (Dictionary, List, etc) you can override IEquatable to provide a type specific version that can do your comparison without boxing or up/down casting. These generic collections will use this overload when present to do comparisons and it can be a bit more efficient.
As noted in the docs, when implementing IEquatable you still need to override Equals/Hashcode from Object.
As everyone else pointed out already, yes, you are correct. In fact, you definitely do not want to override the equality members if your type is mutable (it has setters). But, if you want to have equality checking which uses values in your type, you can make your type immutable (like String) by ensuring that there are no setters (only the constructor sets values). Or use a struct.
For anybody using .Net 5 or later it comes with a ReferenceEqualityComparer class that you can pass to the dictionary's constructor. This means you don't need to worry about someone overriding GetHashCode and Equals in the future.
Yes you are correct doing a == comparison (or .Equals) on two objects compares their references if no other overload is specified.
String s = "a";
object test1 = (object)s;
object test2 = (object)s;
Debug.Assert(test1.Equals(test2));