如何解决如何通过linq将列表中的每个值与另一个列表进行比较
我有两个列表:
ListA ListB
Name Name
marc marc
micheal micheal
Jolie Jolie
我想比较这两个列表A和B,如果它们具有相同的名称,则应该返回true。如果一个列表具有与其他列表不同的值,则应返回false;如果一个列表具有2个值,而另一个具有3个值,则也应返回false。 即使它们具有相同的值,这种特征也会使我始终错误:
var SameNames = ListA.All(x => ListB.All(y => y.Name.Equals(x.Name)));
我做错了吗?请
解决方法
var SameNames = ListA.All(x => ListB.All(y => y.Name.Equals(x.Name)));
您在此处写的是一个要求,即A中的 all 名称必须与B中的 all 名称相匹配。这显然与示例数据相冲突,例如A中的“ Marc”不等于来自B的“朱莉”。
如果A和B总共仅包含一个不同的名称,则您当前的代码将仅返回true。这对于您要解决的问题没有任何意义。
您实际上要解决的问题是,如果A中的所有名称在B中都匹配一个。可以通过以下方式实现:
var sameNames = listA.All(a => listB.Any(b => b.Name.Equals(a.Name)));
请注意Any
。如果找到(至少)一个匹配项,则返回true
。这与All
不同,var listA = new List<string>() { "Andy","Bobby","Cindy" };
var listB = new List<string>() { "Andy","Cindy","David" };
var SameNames = listA.All(a => listB.Any(b => b.Name.Equals(a.Name)));
仅在B中的所有值匹配时返回true。
但是,这还不够。现在,您已经确定A的所有名称都出现在B中,但是B仍然有可能包含更多不在A中的名称。以下面的示例为例:
SameNames
true
将是var listA_in_listB = listA.All(a => listB.Any(b => b.Name.Equals(a.Name)));
var listB_in_listA = listB.All(b => listA.Any(a => a.Name.Equals(b.Name)));
var sameNames = listA_in_listB && listB_in_listA;
,但这是因为您只有一个方向。您需要双向检查:
var listA_in_listB = listA.All(a => listB.Any(b => b.Name.Equals(a.Name)));
var sameLength = listA.Length == listB.Length;
var sameNames = listA_in_listB && sameLength;
这将为您提供所需的结果。
请注意,如何处理此问题还有其他几种方式。
如果您可以保证每个列表都不包含重复项,那么您可以简单地执行一项检查,然后确认列表的长度相同,而不必两次进行相同的检查:
WEEK_BEG_DT ... WEEK_BEG_DT OHTER
0 2013-09-29 ... 2013-09-29 a
1 2013-06-23 ... 2013-09-29 b
2 2012-04-28 ... 2013-09-29 c
3 2013-01-06 ... 2013-09-29 d
4 2013-06-16 ... 2013-09-29 e
这效率更高,但确实需要知道您的名字在每个列表中都是唯一的。
,有一篇关于Microsoft in here
的文章您应该创建函数以比较每个值。变量不是解决方案。
使功能类似于示例:
{
static void Main()
{
// Create the IEnumerable data sources.
string[] names1 = System.IO.File.ReadAllLines(@"../../../names1.txt");
string[] names2 = System.IO.File.ReadAllLines(@"../../../names2.txt");
// Create the query. Note that method syntax must be used here.
IEnumerable<string> differenceQuery =
names1.Except(names2);
// Execute the query.
Console.WriteLine("The following lines are in names1.txt but not names2.txt");
foreach (string s in differenceQuery)
Console.WriteLine(s);
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
/* Output:
The following lines are in names1.txt but not names2.txt
Potra,Cristina
Noriega,Fabricio
Aw,Kam Foo
Toyoshima,Tim
Guy,Wey Yuan
Garcia,Debra
*/
,
您可以使用var SameNames = ListA.SequenceEquals(ListB)
。这将使用对象中定义的默认等于。如果两个对象中的任何一个为空,它将引发异常。因此,请确保您的列表不为空。
等于实现
class YourListItem {
public string Name { get; set; }
public override bool Equals(object obj)
{
if(obj is YourListItem other) {
return this.Name == other.Name;
}
return false;
}
public override int GetHashCode() => this.Name.GetHashCode();
}
如果您需要的定制比较逻辑不能真正“适合”对象equals
方法,或者您需要多个不同的相等实现。您可以创建另一个为您的类型实现IEqualityComparer
的类,并将其作为第二个参数var SameNames = ListA.SequenceEquals(ListB,new MyEqualityComparer())
传递。
平等比较器
class MyEqualityComparer: IEqualityComparer<YourListItem> {
public bool Equals(YourListItem first,YourListItem second) {
return first.Name == second.Name;
}
public int GetHashCode(YourListItem obj) => obj.Name.GetHashCode();
}
注意:覆盖Equals时,还应该始终实现GetHashCode。如果哈希码不相同,则它就像一个较短的等号(从某种意义上来说)等号是多余的,不需要执行。如果HashCode不同,则许多使用EqualityComparers或Equals的预构建方法将无法运行Equals。默认的HashCode是Object引用,因此它会错误地匹配两个列表,使它们实际上不应该等于Equal(如果您不覆盖HashCode)。对于您的HashCode实现,为大多数对象选择一个您认为不同的字段。如果您有一个像这样的微小对象,它看起来很愚蠢,但是您可以拥有庞大的对象,这些对象具有复杂的Equals实现或缓慢的基于通用反射的相等性检查。因此,在大多数情况下,能够在HashCode不相同的情况下完全跳过Equality检查是很重要的。
,如果订单应该相关:
bool result = Enumerable.SequenceEquals<string>(ListA,ListB);
如果订单无关紧要:
bool result = new HashSet<string>(ListA).SetEquals(ListB);
这样做在LINQ中太复杂了,只是调整过头,此时您可以使用ForEachs。如果您想要一个简单干净的解决方案,那么这些都适合您。
问候
,以下是满足您要求的代码。
var isEqual = ListA.OrderBy(o=>o.Name).SelectMany(x=>x.Name).SequenceEqual(ListB.OrderBy(o=>o.Name).SelectMany(x => x.Name));
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。