1

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)
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Afroanton
  • 13
  • 2
  • So you just want a key that uniquely identifies the list in the dictionary. YOu could make a string like tster answer, or you could use the list hashcode. (via `list.GetHashCode()` )There is a v small chance that its not unique tho – pm100 Mar 24 '22 at 23:04
  • How many values do you expect that each list will have on average? Is it possible that a list can have a large number of values, like hundreds or thousands? Also is it possible that more values will be added in a list, after is has been inserted in the dictionary as key? – Theodor Zoulias Mar 25 '22 at 23:00
  • Related: [​How to use a primitive list or List as a key of a dictionary in C#](https://stackoverflow.com/questions/36392631/how-to-use-a-primitive-list-or-list-as-a-key-of-a-dictionary-in-c-sharp) – Theodor Zoulias Mar 25 '22 at 23:03

2 Answers2

3

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

Hero Wanders
  • 3,237
  • 1
  • 10
  • 14
  • You are right @Progman -- this isn't even my code though - I've just collected information. Nevertheless, I will adjust it :) – Hero Wanders Mar 25 '22 at 21:58
2

The easiest solution would be to just serialize the list of ints 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
Progman
  • 16,827
  • 6
  • 33
  • 48
tster
  • 17,883
  • 5
  • 53
  • 72