【问题标题】:Not-hash-based set collection for storing unique objects with custom equality comparer - C#用于存储具有自定义相等比较器的唯一对象的非基于哈希的集合集合 - C#
【发布时间】:2013-03-06 15:57:09
【问题描述】:

我正在尝试将 (name: string, value: long) 对存储在一个集合中。

public class NameValuePair
{
  public string name;
  public long value;
}

public NameValuePairComparer comparer = new NameValuePairComparer();
public HashSet<NameValuePair> nameValueSet = new HashSet<NameValuePair>(comparer);

如果两个对具有相同的名称或相同的值,则它们是相等的 - 这在 NameValuePairComparer 中实现,覆盖 EqualityComparer 的 Equals 方法:

public class NameValuePairComparer : EqualityComparer<NameValuePair>
{
   public override bool Equals(NameValuePair x, NameValuePair y)
   {
      return (x.value == y.value) || (x.name == y.name);
   }

问题是:GetHashCode(NameValuePair obj) 应该为 Equals 返回 true 的两个对象返回相同的值,因此对于给定的 NameValuePair,GetHashCode() 应该返回 value.GetHashCode() 或 name.GetHashCode(),但是为此,我们必须知道两对中的哪个字段相等:

   public override int GetHashCode(NameValuePair obj)
   {
      /* ??? */
      /* // Using unknown reference to x
        if (obj.value == x.value) return obj.value.GetHashCode();
        else if (obj.name == x.name) return obj.name.GetHashCode();
        else return base.GetHashCode(obj);
      */
   }
}

但我们不知道这一点,这意味着我不能使用 HashSet 来存储这些对,也不能使用 EqualityComparer。

问:C# (.net 3.5) 中是否有非基于哈希的 set 实现?

问:使用自定义相等比较器存储唯一 NameValuePair 的更好方法是什么?

【问题讨论】:

    标签: c# collections set unique iequalitycomparer


    【解决方案1】:

    如果两个对具有相同的名称或相同的值,则它们是相等的

    您根本无法使用这些标准正确实施IEqualityComparer&lt;T&gt;。来自Equals的文档:

    Equals 方法具有自反性、对称性和传递性。也就是说,如果用于将对象与自身进行比较,则返回true;如果对 y 和 x 为真,则对两个对象 x 和 y 为真;如果对 x 和 y 为真,对 y 和 z 也为真,则对两个对象 x 和 z 为真。

    现在考虑对:

    x = { "A", 10 },
    y = { "A", 20 },
    z = { "B", 20 }
    

    您是说xy 必须相等,因为它们具有相同的名称,yz 必须相等,因为它们具有相同的值。这意味着(通过传递性)xz 应该相等。

    由于您无法正确实现 IEqualityComparer&lt;T&gt;,因此您不应期望任何依赖于该正确性的东西都能正常工作。

    我怀疑您会发现,如果您更详细地查看您的需求,他们要么真的需要两个集合(一个按名称,一个按值) 从传递性的角度来看,它们没有意义。

    例如,假设您有一个具有您建议的特征的集合,并且您添加了上面的三个元素。如果您按 { x, y, z } 的顺序添加它们,您最终会得到一个条目。如果您按 { z, x, y } 的顺序添加它们,您最终会得到两个。那是一种有用的集合吗?

    【讨论】:

    • @Jon:+1,说真的,你觉得这样的闪电速度如何:)?
    • 传递性在这里并不重要。在您的示例中,如果集合中有 x,我不能允许向其中添加“y”。如果集合中有“y”,我不能允许添加“z”或“x”。所以我认为设置自定义相等比较器将是最好的解决方案。
    • 如果我以 {x,y,z} 或 {z,x,y} 的顺序添加它们,我最终会得到 {x,z} 或 {z,x}。跨度>
    • @MariuszCeier:好的,所以你不做替换:所以按 { y, x, z } 顺序添加它们,你只会得到一个条目。再说一次,这是一件好事吗?传递性对 可能并不重要,但它是IEqualityComparer&lt;T&gt; 中表示的等式关系的要求,因此您不应该实现该接口。鉴于您有奇怪的要求,您不应该期望它们在框架中得到满足。
    • 以 {y,x,z} 顺序添加它们时以单个条目结尾是一件好事,因为一对中的名称和值是 1-1 关系。考虑类枚举类型——这种类型中的每个条目都是一个名称-值对。这些条目在此类型中必须具有唯一名称和唯一值,因此当此类型中有“y”时,“x”和“z”应返回错误(名称冲突或值冲突)。我不必使用 IEqualityComparer,我只需要一个集合集合,它允许我在不定义 HashCode 的情况下指定相等比较器,类似于 C++ 中的 std::set。
    猜你喜欢
    • 2012-01-19
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多