Hi I'm trying to use a Dictionary
with a list of integers as key where the order of the values in the list should matter. So if a have something like this:
List<int> list1 = new List<int>();
list1.Add(1);
list1.Add(2);
list1.Add(3);
List<int> list2 = new List<int>();
list2.Add(1);
list2.Add(2);
list2.Add(3);
Dictionary<List<int>,int> dictionary = new Dictionary<List<int>,int>();
dictionary.Add(list2 , 100);
I want to be able to access the value in the dictionary with list2
. So in term of functionality I want it to work similar to
Enumerable.SequenceEqual(list1, list2)
CodePudding user response:
You should build your Dictionary
using the constructor accepting an IEqualityComparer
.
In the implementation of that IEqualityComparer
you should use SequenceEqual
instead of / in addition to standard equality.
Example (on C# PlayGround):
public class EnumerableComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return Object.ReferenceEquals(x, y) || (x != null && y != null && x.SequenceEqual(y));
}
public int GetHashCode(IEnumerable<T> obj)
{
unchecked
{
return obj.Where(e => e != null).Select(e => e.GetHashCode()).Aggregate(17, (a, b) => 23 * a b);
}
}
}
var key1 = new List<int> { 1, 3, 5 };
var key2 = new List<int> { 2, 4, 6 };
var key3 = new List<int> { 1, 3, 5 };
var comparer = new EnumerableComparer<int>();
var dictionary = new Dictionary<List<int>, string>(comparer);
dictionary.Add(key1, "hello");
dictionary.Add(key2, "world");
Console.WriteLine(dictionary[key3]); // prints "hello"
Info: A quick research shows that the mentioned Dictionary
constructor is available since at least .NET Framework 2.0. It's available in all versions up to the most current one (at the time of writing: .NET 6).
Update (2022-03-25): renamed IEnumerableComparer
to EnumerableComparer
CodePudding user response:
The easiest solution would be to just serialize the list of int
s into a string
.
For example:
Dictionary<string,int> dictionary = new Dictionary<string,int>();
dictionary.Add(string.Join(",", list2), 100);
You could do a less hacky thing where you define your own class which encapsulates the list and properly implements GetHashCode()
and Equals()
. important: You will need to be careful with this class since lists are mutable. If you insert something into the list after you have added the item to the dictionary you won't get the expected behavior:
For example:
List<int> list1 = new List<int>();
list1.Add(1);
list1.Add(2);
list1.Add(3);
MyListWrapper wrapper1 = new MyListWrapper(list1);
List<int> list2 = new List<int>();
list2.Add(1);
list2.Add(2);
list2.Add(3);
MyListWrapper wrapper2 = new MyListWrapper(list2);
Dictionary<MyListWrapper,int> dictionary = new Dictionary<MyListWrapper,int>();
dictionary.Add(wrapper1, 100);
Assert.AreEqual(100, dictionary[wrapper2]); // this will work
list1.Add(5);
list2.Add(5);
Assert.AreEqual(100, dictionary[wrapper2]); // this will NOT work