【问题标题】:C#: Dictionary indexed by ListC#:由 List 索引的字典
【发布时间】:2011-11-10 14:54:20
【问题描述】:

我尝试编写一个程序,其中 Dictionary 由 List 索引。 (相信我,是的,有选项,但我喜欢按列表索引)。有一个最小的工作(实际上不工作,只有最后一行是一个问题)示例:

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]);
    }
}

如果调试这个程序,他会清楚地看到 h 中有两个元素,但仍然无法通过正确的索引访问这些元素 --- h[w]。是我错了还是发生了什么奇怪的事情?

【问题讨论】:

  • 列表类可能不会根据其内容生成哈希码和相等性检查。您是否检查过数组是否工作得更好?
  • 或者使用自定义类,或者Tuple&lt;T, T2....&gt;
  • 不,数组具有相同的行为。
  • 你可能需要一个自定义的 IEqualityComparer
  • @LasseV.Karlsen:他们不会:ideone.com/7Gvvh

标签: c# list dictionary indexed


【解决方案1】:

您的应用程序的问题在于:

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

列表的相等性检查两个引用是否引用同一个实例。在这种情况下,他们没有。相反,您创建了两个具有相同元素的列表...这不会使它们相等。

您可以通过创建自定义平等比较器来解决问题:

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;
    }
}

然后将其传递给 Dictionary 构造函数:

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

【讨论】:

  • 通常在比较两个引用类型时,如果两个引用指向同一个对象,比较返回true。如果对象不同,那么即使它们的内容相同,结果也会是错误的。
  • 另一种选择是使用ToArray()IStructuralEquatable.GetHashCode 来实现更简单(如果更慢)。 (或者可能使用数组和 Dictionary&lt;IStructuralEquatable, int&gt; 开头。)
  • 谢谢!像魅力一样工作,它只是for(var i = 1; i &lt; list.Length; i++)
【解决方案2】:

问题是 List 的索引,您索引的不是列表中的数据,而是您实际上是通过指向 List 的内存指针(即该 List 所在的内存地址)进行索引。

您在一个内存位置创建了一个列表,然后在不同的内存位置创建了一个完全不同的列表(即当您创建一个新实例时)。这两个列表是不同的,即使它们包含相同的数据,这意味着您可以将任意数量的数据添加到字典中。

一种解决方案不是按列表索引而是按字符串索引并使用逗号分隔的列表,其中包含列表中的所有数据作为索引。

【讨论】:

  • 技术上不是指针,但这是正确的。 List 不会根据内容计算哈希码:ideone.com/AEIDO
【解决方案3】:

这对你永远不起作用,因为List&lt;T&gt;EqualsGetHashCode 方法不考虑列表的内容。如果您想使用对象集合作为键,您需要实现自己的集合类型来覆盖Equals,以便检查集合中对象的相等性(可能使用Enumerable.SequenceEqual. )

【讨论】:

  • 哦,或者你可以使用IEqualityComparer,就像上面提到的评论中的那个人一样,但我会把它留给其他人。
【解决方案4】:

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

【讨论】:

  • 在这个特定的上下文中。一般来说,它不会这样做,但是对于不覆盖 GetHashCode 或 Equals 的列表,它会这样做。
猜你喜欢
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
  • 1970-01-01
  • 2016-05-25
  • 2017-03-17
  • 2022-10-26
  • 2021-10-08
相关资源
最近更新 更多