简体   繁体   English

C#:按列表索引的字典

[英]C#: Dictionary indexed by List

I try to write a program where Dictionary is indexed by List. 我尝试编写一个程序,其中Dictionary由List索引。 (trust me i do, and yes there are option, but i like indexing by list). (相信我,我愿意,是的,有选择,但是我喜欢按列表编制索引)。 There is a minimal working (actually not working, only one last line which is a problem) example: 有一个最小的工作(实际上不工作,只有最后一行是一个问题)示例:

using System;
using System.Collections.Generic;

namespace test
{
    class Program
    {
    static void Main(string[] args)
    {
        Dictionary<List<String>, int> h = new Dictionary<List<string>,int>();

        List<String> w = new List<string> {"a"};
        h.Add(w, 1);

        w = new List<string>{"b"};
        h.Add(w,2);

        w = new List<string>{"a"};

        int value = 0;
        h.TryGetValue(w, out value);
        Console.WriteLine(value+" "+h[w]);
    }
}

if one debugs this program, he will clearly see that there two elements in h, but still these elements are not accessible via correct indexes --- h[w]. 如果有人调试该程序,他将清楚地看到h中有两个元素,但是仍然无法通过正确的索引--- h [w]访问这些元素。 Am I wrong or is there something weird going on? 我是错了还是发生了什么奇怪的事情?

The problem with your app extends from the fact that: 您的应用程序的问题源于以下事实:

new List<String> { "a" } != new List<String> { "a" }

Equality for lists checks to see if the two references refer to the same instance. 列表是否相等将检查两个引用是否引用同一实例。 In this case, they don't. 在这种情况下,他们没有。 You've instead created two Lists with the same elements...which doesn't make them equal. 相反,您创建了两个具有相同元素的列表...这并不使它们相等。

You can fix the problem by creating a custom Equality Comparer: 您可以通过创建自定义的“平等比较器”来解决此问题:

public class ListEqualityComparer<T> : IEqualityComparer<List<T>>
{
    public bool Equals(List<T> list1, List<T> list2)
    {
        return list1.SequenceEquals(list2);
    }

    public int GetHashCode(List<T> list)
    {
        if(list != null && list.Length > 0)
        {
            var hashcode = list[0].GetHashCode();
            for(var i = 1; i <= list.Length; i++)
                hashcode ^= list[i].GetHashCode();

            return hashcode;
        }

        return 0;
    }
}

And then passing that to the Dictionary constructor: 然后将其传递给Dictionary构造函数:

Dictionary<List<String>, int> h = 
    new Dictionary<List<string>,int>(new ListEqualityComparer<String>());

The problem is the index by List, what you are indexing by isn't the data in the list but you are essentially indexing by the memory pointer to the List (ie the memory address of where this List is located). 问题是按列表进行索引,您要按的索引不是列表中的数据,但实际上您是通过指向该列表的内存指针(即此列表所在的内存地址)进行索引的。

You Created one list at one memory location, you then created a totally different list at a different memory location (ie when you create a new instance). 您在一个内存位置创建了一个列表,然后在另一个内存位置(即,创建新实例时)创建了一个完全不同的列表。 The two lists are different even though they contain the same data, and this means you can add as many as you want to the dictionary. 这两个列表即使包含相同的数据也有所不同,这意味着您可以向词典中添加任意数量的列表。

One solution is Rather than indexing by List would be to index by String and use a comma separated List containing all the data in your list as an index. 一种解决方案是,不是按列表编制索引,而是按字符串编制索引,并使用逗号分隔的包含您列表中所有数据的List作为索引。

This won't ever work for you, because List<T> 's Equals and GetHashCode methods don't consider the contents of the list. 这将永远无法为您服务,因为List<T>EqualsGetHashCode方法不考虑列表的内容。 If you want to use a collection of objects as a key, you'll need to implement your own collection type that overrides Equals in such a way as to check the equality of the objects in the collection (perhaps using Enumerable.SequenceEqual .) 如果要将对象集合用作键,则需要实现自己的集合类型,该类型将覆盖Equals ,以便检查集合中对象的相等性(也许使用Enumerable.SequenceEqual 。)

Dictionary类使用引用比较来查找指定的键,这就是为什么即使列表包含相同项,它们也不同的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM