C# 如何比较一个属性上两个共享的哈希集?

C# 如何比较一个属性上两个共享的哈希集?,c#,hashset,C#,Hashset,我需要比较两个hashset,它们的类型相同,但只有一些属性的值不同。我需要一个更具体的例外 我已经尝试使用ExceptWith,但据我所知,它不允许您指定要比较的属性 我们应该假装我不能向Person类添加或删除任何属性 class Program { private class Person { public string Name { get; set; } public string Id { get; set; } }

我需要比较两个hashset,它们的类型相同,但只有一些属性的值不同。我需要一个更具体的例外

我已经尝试使用ExceptWith,但据我所知,它不允许您指定要比较的属性

我们应该假装我不能向Person类添加或删除任何属性

   class Program
{
    private class Person
    {
        public string Name { get; set; }
        public string Id { get; set; }
    }

    static void Main(string[] args)
    {
        var people1 = new[]
        {
            new Person
            {
                Name = "Amos",
                Id = "123"
            },
            new Person
            {
                Name = "Brian",
                Id = "234"
            },
            new Person
            {
                Name = "Chris",
                Id = "345"
            },
            new Person
            {
                Name = "Dan",
                Id = "456"
            }
        };

        var people2 = new[]
        {
            new Person
            {
                Name = "Amos",
                Id = "098"
            },
            new Person
            {
                Name = "Dan",
                Id = "987"
            }
        };

        var hash1 = new HashSet<Person>(people1);

        var hash2 = new HashSet<Person>(people2);

        var hash3 = new HashSet<Person>(); // where hash3 is hash1 without the objects from hash2 solely based on matching names, not caring about Id matching

        foreach (var item in hash3) // should print out Brian, Chris
        {
            Console.WriteLine($"{item.Name}");
        }
    }
}
类程序
{
私人阶级人士
{
公共字符串名称{get;set;}
公共字符串Id{get;set;}
}
静态void Main(字符串[]参数)
{
var people1=新[]
{
新人
{
Name=“Amos”,
Id=“123”
},
新人
{
Name=“Brian”,
Id=“234”
},
新人
{
Name=“克里斯”,
Id=“345”
},
新人
{
Name=“Dan”,
Id=“456”
}
};
var people2=新[]
{
新人
{
Name=“Amos”,
Id=“098”
},
新人
{
Name=“Dan”,
Id=“987”
}
};
var hash1=新的HashSet(people1);
var hash2=新的HashSet(people2);
var hash3=new HashSet();//其中hash3是hash1,没有来自hash2的对象,仅基于匹配的名称,不考虑Id匹配
foreach(hash3中的var项)//应该打印出Brian,Chris
{
Console.WriteLine($“{item.Name}”);
}
}
}

Person
类中,您应该定义自己的
GetHashCode
方法,以便它只使用人的名字而不使用ID


如果这样做,您还必须定义自己的
Equals
方法:

您可以使用linq执行此操作:

var hash3 = hash1.Where(x=>!hash2.Select(y=>y.Name).Contains(x.Name)).ToHashSet();

这将创建一个仅包含来自hash2的名称的集合,然后获取来自hash1的所有人员,其中该名称不在该集合中

您只需对第二个数组中的名称进行散列,以便在Linq筛选器中使用,从而创建最终的
散列集

var excludeName = new HashSet<string>(people2.Select(x => x.Name));
var hash3 = new HasSet<Person>(people1.Where(x => !exludeName.Contains(x.Name));
注意:这意味着即使
Id
不同,
HashSet
s也不能包含两个具有相同
名称的项。但这也意味着它不能像当前设置那样包含具有相同值的不同对象

然后像这样使用它

var comparer = new PersonByNameComparer();

var hash1 = new HashSet<Person>(people1, comparer);
var hash2 = new HashSet<Person>(people2, comparer);

// Note that ExceptWith will mutate the existing hash.  
hash1.ExceptWith(hash2); 

// Alternatively you can create the new hash like this
var hash3 = new HashSet<Persion>(hash1.Where(p => !hash2.Contains(p)));
var comparer=newPersonByNameComparer();
var hash1=新的HashSet(people1,comparer);
var hash2=新的HashSet(people2,comparer);
//请注意,ExceptWith将改变现有哈希。
hash1.ExceptWith(hash2);
//或者,您可以像这样创建新的哈希
var hash3=新的HashSet(hash1.Where(p=>!hash2.Contains(p));

您可以使用
IEqualityComparer
设置哈希值,确定如何确定项目的相等性(我假设您希望它在名称上?)。对于一个清晰的问题,使用最简单的工作示例,使用最高分@朱哈尔:你有在类似场景中实现IEqualityComparer的例子吗?@CoreyC。我更新了我的答案,加入了一个例子。
hash3
在这里是一个
IEnumerable
,而不是
HashSet
。啊,你在问题中没有说,你只是说“应该打印出Brian,Chris”。只需要
.ToHashSet()
最后,我会编辑答案。不是我的问题。我刚刚指出,您有一个名为
hash3
的变量,它实际上不是
HashSet
。我认为juharr的意思是,在您的解决方案中
hash3
是一个
IEnumerable
,而他们希望它是一个
HashSet
。这在他们的示例代码中明确指出,
var hash3=HashSet()
应该注意,这是一个多项式算法,因为它必须对
hash1
中的每个项迭代
hash2
。对于像示例中这样的小集合,这不是问题,但扩展性不太好。这似乎是该用例的最佳方式,但在我的实际场景中,我无法编辑该类。我将把这一点补充到问题中。谢谢
var comparer = new PersonByNameComparer();

var hash1 = new HashSet<Person>(people1, comparer);
var hash2 = new HashSet<Person>(people2, comparer);

// Note that ExceptWith will mutate the existing hash.  
hash1.ExceptWith(hash2); 

// Alternatively you can create the new hash like this
var hash3 = new HashSet<Persion>(hash1.Where(p => !hash2.Contains(p)));