c# - HashSet类型如何使用ExceptWith> 在 C# 中?
问题描述
HashSet<ReadOnlyCollection<int>> test1 = new HashSet<ReadOnlyCollection<int>> ();
for (int i = 0; i < 10; i++) {
List<int> temp = new List<int> ();
for (int j = 1; j < 2; j++) {
temp.Add (i);
temp.Add (j);
}
test1.Add (temp.AsReadOnly ());
}
这里 test1 是 {[0,1], [1,1], [2,1], [3,1], [4,1], [5,1], [6,1], [7,1 ], [8,1], [9,1]}
HashSet<ReadOnlyCollection<int>> test2 = new HashSet<ReadOnlyCollection<int>> ();
for (int i = 5; i < 10; i++) {
List<int> temp = new List<int> ();
for (int j = 1; j < 2; j++) {
temp.Add (i);
temp.Add (j);
}
test2.Add (temp.AsReadOnly ());
}
这里 test2 是 {[5,1], [6,1], [7,1], [8,1], [9,1]}
test1.ExceptWith(test2);
这样做之后,我希望 test1 是 {[0,1], [1,1], [2,1], [3,1], [4,1]},但它给了我原来的 test1。
如何解决这个问题?或者有没有其他方法可以做同样的事情?谢谢!
解决方案
c# 中的对象通常按引用进行比较,而不是按值进行比较。这意味着new object() != new object()
. 以同样的方式,new List<int>() { 1 } != new List<int>() { 1 }
。另一方面,结构体和原语是按值进行比较,而不是按引用进行比较。
一些对象会覆盖它们的相等方法来比较值。例如字符串:new string(new[] { 'a', 'b', 'c'}) == "abc"
,即使object.ReferenceEquals(new string(new[] { 'a', 'b', 'c'}), "abc") == false
.
但是集合、列表、数组等没有。有充分的理由 - 在比较两个整数列表时,你想比较什么?确切的元素,无论顺序如何?按顺序排列的确切元素?元素的总和?没有一个答案适合所有事情。通常你可能真的想检查你是否有相同的对象。
使用集合或 LINQ 时,您通常可以指定一个自定义“比较器”,它将按照您想要的方式处理比较。然后,收集方法在需要比较两个元素时使用这个“比较器”。
一个非常简单的适用于 a 的比较器ReadOnlyCollection<T>
可能如下所示:
class ROCollectionComparer<T> : IEqualityComparer<IReadOnlyCollection<T>>
{
private readonly IEqualityComparer<T> elementComparer;
public ROCollectionComparer() : this(EqualityComparer<T>.Default) {}
public ROCollectionComparer(IEqualityComparer<T> elementComparer) {
this.elementComparer = elementComparer;
}
public bool Equals(IReadOnlyCollection<T> x, IReadOnlyCollection<T> y)
{
if(x== null && y == null) return true;
if(x == null || y == null) return false;
if(object.ReferenceEquals(x, y)) return true;
return x.Count == y.Count &&
x.SequenceEqual(y, elementComparer);
}
public int GetHashCode(IReadOnlyCollection<T> obj)
{
// simplistic implementation - but should OK-ish when just looking for equality
return (obj.Count, obj.Count == 0 ? 0 : elementComparer.GetHashCode(obj.First())).GetHashCode();
}
}
然后您可以比较默认相等检查的行为和您自定义的行为:
var std = new HashSet<int[]>(new[] { new[] { 1, 2 }, new[] { 2, 2}});
std.ExceptWith(new[] { new[] { 2, 2}});
std.Dump();
var custom = new HashSet<int[]>(new[] { new[] { 1, 2 }, new[] { 2, 2 } }, new ROCollectionComparer<int>());
custom.ExceptWith(new[] { new[] { 2, 2 }});
custom.ExceptWith(new[] { new int[] { }});
custom.Dump();
你可以在这个小提琴中测试整个事情。
推荐阅读
- ios - 从 iOS 中的文本视图中删除单行
- python - Scrapy 加载不会将所有信息加载到 postgres 中。为什么?
- python - 在两个字符串之间拆分正则表达式 python,但包含使用 re.split 并返回一个列表
- python - 在 Keras 中训练 GAN 时,是否需要多次通过来优化生成器和判别器?
- android - 将kotlin数据类转换为json字符串
- javascript - 从 expo-video-player 获取“setAudioModeAsync 错误”
- python-3.x - 根据公共列上的匹配值合并 2 个 CSV 文件并将组合的新集合写入新的 CSV 文件
- mocking - 开玩笑模拟exports.name 无法正常工作
- angular - 关于在组件中直接更新服务数据的问题
- php - Wordpress 城市前缀到 url 作为子域和子页面