我在比较两个列表时遇到了问题。我有两个海关对象列表,我希望它们之间有区别,然后计算结果的数量。这是一个例子:
这是我的自定义类:
public class Contact
{
public String FirstName { get; set; }
public String LastName { get; set; }
public bool IsAdmin { get; set; }
}
在我的应用程序中,当我在两个List It之间产生差异时听起来像这样:
List<Contact> Difference =
List1.Where(Second =>
!List2.Any(First =>
First.FirstName == Second.FirstName
&& First.LastName == Second.LastName
&& First.IsAdmin == Second.IsAdmin))
.ToList();
这个方法给出了与条件匹配的结果,所以我可以对结果进行分组和计数,除非我有这样的结果:
List<Contact> List1 = new List<Contact>
{
new Contact { Firstname = "Tom", LastName = "Smith", IsAdmin = true },
new Contact { Firstname = "Tom", LastName = "Smith", IsAdmin = true },
new Contact { Firstname = "Bob", LastName = "Smith", IsAdmin = false },
new Contact { Firstname = "Vincent", LastName = "Smith", IsAdmin = false }
};
List<Contact> List2 =new List<Contact>
{
new Contact { Firstname = "Tom", LastName = "Smith", IsAdmin = true},
new Contact { Firstname = "Bob", LastName = "Smith", IsAdmin = false}
};
当我运行我的方法时,我得到1个结果:
new Contact { Firstname = "Vincent", LastName = "Smith", IsAdmin = false }
因为它符合条件 但我希望这是结果:
new Contact { Firstname = "Tom", LastName = "Smith", IsAdmin = true}
new Contact { Firstname = "Vincent", LastName = "Smith", IsAdmin = false }
你怎么能让它变得可能?
编辑:工作方法:
var groups1 = List1
.GroupBy(c => new { c.Firstname, c.LastName, c.IsAdmin });
var groups2 = List2
.GroupBy(c => new { c.Firstname, c.LastName, c.IsAdmin });
var diffs = from g1 in groups1
join g2 in groups2
on g1.Key equals g2.Key into gj
from g2 in gj.DefaultIfEmpty(Enumerable.Empty<Contact>())
where g1.Count() > g2.Count()
select new { g1, g2 };
List<Contact> allDiffs = diffs
.SelectMany(x => x.g1.Take(x.g1.Count() - x.g2.Count()))
.ToList();
答案 0 :(得分:1)
如果您需要两个列表中的公共项目,请删除negation operator
List<Contact> Difference =
Contact_List2.Where(Second =>
Contact_List1.Any(First =>
First.FirstName == Second.FirstName
&& First.LastName == Second.LastName
&& First.IsAdmin == Second.IsAdmin))
.ToList();
答案 1 :(得分:1)
也许你想要list1中但不在list2中的所有项目,即使是list2中但不是相同数量的项目,请尝试:
var groups1 = List1
.GroupBy(c => new { c.Firstname, c.LastName, c.IsAdmin });
var groups2 = List2
.GroupBy(c => new { c.Firstname, c.LastName, c.IsAdmin });
var diffs = from g1 in groups1
join g2 in groups2
on g1.Key equals g2.Key into gj
from g2 in gj.DefaultIfEmpty(Enumerable.Empty<Contact>())
where g1.Count() > g2.Count()
select new { g1, g2 };
List<Contact> allDiffs = diffs
.SelectMany(x => x.g1.Take(x.g1.Count() - x.g2.Count()))
.ToList();
(编辑:我希望有一种更简单的方法,但它有效)
答案 2 :(得分:0)
你真正想要的是一个交集,LINQ可以使用Intersect方法,但要使用自定义对象,你需要实现IEquatable<T>
(或实现自己的自定义{{} 1}})。
这样您就可以简单地致电IEqualityComparer<T>
,了解您的代码目前失败的原因......
var difference = List2.Intersect(List1)
您要求List<Contact> Difference = Contact_List2.Where(Second =>
!Contact_List1.Any(First =>
First.FirstName == Second.FirstName
&& First.LastName == Second.LastName
&& First.IsAdmin == Second.IsAdmin))
.ToList();
中的List2
中的所有记录List1
中的不是 - 您想要的是List2
中的所有记录{strong}也是<{1}}中的。
要修复,只需从List1
检查中删除!
(非)运算符即可。
Any
答案 3 :(得分:0)
或者,您可以将Enumerable.Intersect
与自定义相等比较器一起使用。它将生成两个列表中找到的IEnumerable<T>
个项目。你会这样使用它:
var matching = List1.Intersect(List2, new ContactComparer());
自定义比较器(无耻地提升并改编自MSDN docs):
public sealed class ContactComparer : IEqualityComparer<Contact>
{
public bool Equals(Contact x, Contact y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.FirstName == y.FirstName &&
x.LastName == y.LastName &&
x.IsAdmin == y.IsAdmin;
}
public int GetHashCode(Contact contact)
{
if (Object.ReferenceEquals(contact, null)) return 0;
//Get hash code for the Name field if it is not null.
int hashContactFirst = contact.FirstName == null ? 0 : contact.FirstName.GetHashCode();
//Get hash code for the Code field.
int hashContactLast = contact.LastName == null ? 0 : contact.LastName.GetHashCode()
int hashAdmin = contact.IsAdmin.GetHashCode();
return hashContactFirst ^ hashContactLast ^ hashAdmin;
}
}
我个人赞成这条路线,因为它创造了更易读的linq,通过快速浏览更容易理解。
答案 4 :(得分:0)
我不确定单独使用LINQ是多么容易。我认为下面的代码给出了你想要的结果。当然,它实际上正在改变List1,因此如果您需要原始列表,则需要处理副本。
foreach (Contact contact2 in List2)
{
List1.Remove(List1.FirstOrDefault(contact1 => contact1.FirstName == contact2.FirstName
&& contact1.LastName == contact2.LastName
&& contact1.IsAdmin == contact2.IsAdmin));
}