【问题标题】:ContainsKey in dictionary of hashset<myClass>containsKey 在 hashset<myClass> 的字典中
【发布时间】:2016-08-25 06:32:00
【问题描述】:

我有一本字典:

Dictionary<HashSet<myClass>, List<MyObj>> myDict = ...

我有:

HashSet<myClass> myHashSet = ...

我想检查字典 (myDict) 是否包含 myHashSet。

我尝试覆盖两种方法:

1) 相等

2) 获取哈希码

public class myClass
{
    public string id;
    public int number;

    public override bool Equals(object obj)
    {
        myClass other = obj as myClass;
        bool ret = false;
        if (other != null)
        {
            ret = (this.number == other.number) && (this.id == other.id);
        }
        return ret;
    }

    public override int GetHashCode()
    {
        return this.number ^ this.id.GetHashCode();
    }
};

不幸的是,在字典中找到的键对代码返回 false: myDict.ContainsKey(myHashSet)

任何帮助表示赞赏!

【问题讨论】:

    标签: c# dictionary hashset containskey


    【解决方案1】:

    仅仅因为你覆盖了myClassEquals(GetHashCode()并不意味着你覆盖了HashSet&lt;myClass&gt;Equals(GetHashCode(),这就是你做字典时使用的东西查找。

    如果您希望它工作,您需要将 IEqualityComparer&lt;HashSet&lt;myClass&gt;&gt; 传递给字典的构造函数,以便在查找字典时使用该比较器。

    public class myClassSetComperer : IEqualityComparer<HashSet<myClass>>
    {
        public bool Equals(HashSet<myClass> x, HashSet<myClass> y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (ReferenceEquals(null, x)) return false;
            if (ReferenceEquals(null, y)) return false;
            return x.SetEquals(y);
        }
    
        public int GetHashCode(HashSet<myClass> obj)
        {
            unchecked
            {
                int x = 0;
                foreach (var myClass in obj)
                {
                    x = (x*397) ^ myClass?.GetHashCode() ?? 0;
                }
                return x;
            }
        }
    }
    
    //elsewhere
    Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>, List<MyObj>>(new myClassSetComperer());
    

    非常重要的提示:如果你做了任何导致Equals(GetHashCode() 在作为查找键输入后发生变化的事情,字典键(和哈希集)就会严重损坏。如果在将 HashSet&lt;myClass&gt;myClass 对象之一放入字典后修改它,您将破坏字典并可能破坏 HashSet。请参阅 Eric Lippert 的 this very good blog post“GetHashCode 指南和规则”

    【讨论】:

      【解决方案2】:

      在比较 myClass 的实例时覆盖 GetHasCode 和 Equal。

      这是一个使用 ContainsKey 的示例,它通过对象引用进行检查。

      Dictionary<HashSet<string>, List<string>> hashSetDictionary = new Dictionary<HashSet<string>, List<string>>();
                  var myHashSet = new HashSet<string>();
      
                  hashSetDictionary.Add(myHashSet, null);
                  Console.WriteLine(hashSetDictionary.ContainsKey(myHashSet));
      

      这是对您的代码的更新

       public class myClass
          {
              public myClass(string text, int num)
              {
                  this.Text = text;
                  this.Num = num;
              }
      
              public string Text { get; set; }
              public int Num { get; set; }
          }
      
          public class MyObj { }
      
          public class AlwaysTrueHashSet<T> : HashSet<T>
          {
              public override bool Equals(object obj)
              {
                  return this.GetHashCode() == obj.GetHashCode();
              }
      
              public override int GetHashCode()
              {
                  return "Counting hashcode".GetHashCode();
              }
          }
      
          class Program
          {
              static void Main(string[] args)
              {
      
      
                  Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>,
      
      
                  List<MyObj>>();
                  var myHashSet1 = new AlwaysTrueHashSet<myClass>();
                  myHashSet1.Add(new myClass("123", 5));
                  myDict.Add(myHashSet1, null);
      
      
      
                  var myHashSet2 = new AlwaysTrueHashSet<myClass>();
                  myHashSet2.Add(new myClass("123", 5));
      
                  /*
                   * when containsKey is invoked, it's checking if the reference of myHashSet2 is the same as myHashSet1.
                   * That's the default behavior.
                   * 
                   * extend HashSet, and override the gethashcode and equal methods  
                   */
                  if (myDict.ContainsKey(myHashSet2))
                  {
                      Console.WriteLine("in");
                      int i = 3; // it doesn't get this line }  
                  }
              }
          }
      

      【讨论】:

      • 当hashset属于一个类时不起作用:Dictionary, List> myDict = new Dictionary, List>() ; HashSet myHashSet1= new HashSet(); myHashSet1.Add(new myClass("123", 5)); myDict.Add(myHashSet1, null); HashSet myHashSet2 = new HashSet(); myHashSet2.Add(new myClass("123", 5)); if (myDict.ContainsKey(myHashSet2)) { int i = 3; // 它没有得到这一行 }
      • 您的代码将始终返回 false。我已经更新了我的代码。
      • 当你覆盖 myClass 时,它只适用于比较 myClass 的两个实例。如果要比较HashSet,则需要对其进行扩展并提供逻辑。否则,它将通过引用进行比较。
      • 你不需要重写 HashSet,只需将 IEqualityComparer&lt;HashSet&lt;myClass&gt;&gt; 传递给字典构造函数,更简单
      • 这只是另一种方式。另外,我想通过覆盖 equal 和 gethashcode 来加强 Erez 对比较对象的理解
      猜你喜欢
      • 1970-01-01
      • 2012-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-26
      • 1970-01-01
      • 2022-01-12
      • 2012-03-12
      相关资源
      最近更新 更多