我知道HashSet<T>.SetEquals
方法,但应该何时以及如何使用CreateSetComparer
?
documentation状态:“仅在一个级别检查相等性;但是,您可以将其他级别的比较器链接在一起以执行更深入的相等性测试”
这是一个简单的例子吗?
特别是,如果我比较的集合中的每个项目也包含HashSet,那么CreateSetComparer
的正确用法是什么?
这是我的出发点。我想知道CreateSetComparer
方法是否适用以及如何正确使用它:
public class Foo : IEquatable<Foo>
{
public string Label { get; set; }
public string Value { get; set; }
public override string ToString() {return String.Format("{0}:{1}", Label, Value); }
// assume for this example that Label and Value are immutable once set;
public override int GetHashCode(){ return ToString().GetHashCode(); }
// simplified equality check; assume it meets my needs for this example;
public bool Equals(Foo other){ return String.Equals(this.ToString(), other.ToString()); }
}
public class FooGroup : IEquatable<FooGroup>
{
public int GroupIndex {get; set;}
public HashSet<Foo> FooCollection {get; set;}
// -----------------------------
// Does HashSet.CreateSetComparer somehow eliminate or simplify the following code?
// -----------------------------
public override int GetHashCode()
{
int hash = GroupIndex;
foreach(Foo f in FooCollection)
hash = hash ^ (f.GetHashCode() & 0x7FFFFFFF);
return hash;
}
public bool Equals(FooGroup other)
{
// ignore missing null checks for this example
return this.GroupIndex == other.GroupIndex && this.FooCollection.SetEquals(other.FooCollection);
}
}
public class GroupCollection : IEquatable<GroupCollection>
{
public string CollectionLabel {get; set;}
public HashSet<FooGroup> AllGroups {get; set;}
// -----------------------------
// Does HashSet.CreateSetComparer somehow eliminate or simplify the following code?
// -----------------------------
public override int GetHashCode()
{
int hash = CollectionLabel.GetHashCode();
foreach(FooGroup g in AllGroups)
hash = hash ^ (g.GetHashCode() & 0x7FFFFFFF);
return hash;
}
public bool Equals(GroupCollection other)
{
// ignore missing null checks for this example
return String.Equals(this.CollectionLabel, other.CollectionLabel) && this.AllGroups.SetEquals(other.AllGroups);
}
}
忽略有关系统设计的论据等,简化的用例是:想象一下,我已经提取了一组如下所示的复杂数据:
var newSetA = new GroupCollection{ ... }
var oldSetA = new GroupCollection{ ... }
我只想查一下:
if (newSetA.Equals(oldSetA))
Process(newSetA);
答案 0 :(得分:3)
让我们从“CreateSetComparer何时有用”的问题开始?你已经有了一个很好的想法:
特别是,如果我比较的集合中的每个项目都包含一个HashSet,那么CreateSetComparer的正确用法是什么?
嗯,例如,下一个示例演示了HashSet
使用其默认比较器时的默认行为(仅通过引用进行比较):
var set1 = new HashSet<HashSet<int>>{
new HashSet<int>{2,3,4},
new HashSet<int>{7,8,9}
};
var set2 = new HashSet<HashSet<int>>{
new HashSet<int>{2,3,4},
new HashSet<int>{7,8,9},
};
set1.SetEquals(set2).Dump(); // false :-(
set1.SequenceEqual(set2).Dump(); // false
set1.SequenceEqual(set2, HashSet<int>.CreateSetComparer()).Dump(); // true
也可以将CreateSetComparer
与SetEquals
一起使用,如下所示:
// the order of elements in the set has been change.
var set1 = new HashSet<HashSet<int>>(HashSet<int>.CreateSetComparer()){
new HashSet<int>{2,3,4},
new HashSet<int>{7,8,9}
};
var set2 = new HashSet<HashSet<int>>{
new HashSet<int>{7,8,9},
new HashSet<int>{2,3,4},
};
set1.SetEquals(set2).Dump(); // true :-)
set1.SequenceEqual(set2).Dump(); // false
set1.SequenceEqual(set2, HashSet<int>.CreateSetComparer()).Dump(); // false
这是通常的用法,但是CreateSetComparer
提供了GetHashCode
你可以利用的,虽然这不一定更短/更清洁,你已经做了。
// -----------------------------
// Does HashSet.CreateSetComparer somehow eliminate or simplify the following code?
// -----------------------------
private IEqualityComparer<HashSet<FooGroup>> _ecomparer =
HashSet<FooGroup>.CreateSetComparer();
public override int GetHashCode()
{
int hash = CollectionLabel.GetHashCode();
hash ^= _ecomparer.GetHashCode(AllGroups);
return hash;
}
答案 1 :(得分:2)
我在向词典提供&#34;多个&#34;时使用过它。订单无关紧要的密钥:
var dict = new Dictionary<HashSet<int>, string>(HashSet<int>.CreateSetComparer());
dict[new HashSet<int> { 1, 2 }] = "foo";
dict[new HashSet<int> { 2, 1 }].Dump();
您可以使用params
索引器包装它来提供更好的API:
public class MultiKeyDictionary<TKey, TValue> : IDictionary<HashSet<TKey>, TValue>
{
private readonly IDictionary<HashSet<TKey>, TValue> _dict;
public MultiKeyDictionary()
{
_dict = new Dictionary<HashSet<TKey>, TValue>(HashSet<TKey>.CreateSetComparer());
}
public TValue this[params TKey[] keys]
{
get { return _dict[new HashSet<TKey>(keys)]; }
set { _dict[new HashSet<TKey>(keys)] = value; }
}
...
}
var dict = new MultiKeyDictionary<int, string>();
dict[1, 2] = "foo";
dict[2, 1].Dump();