ฉันมีรายการทั่วไปสองรายการที่เต็มไปด้วย CustomsObjects
ฉันต้องการดึงความแตกต่างระหว่างสองรายการ (รายการที่อยู่ในรายการแรกโดยไม่มีรายการในรายการที่สอง) ในรายการที่สาม
ฉันคิดว่าการใช้.Except()เป็นความคิดที่ดี แต่ฉันไม่เห็นวิธีใช้นี้ .. ช่วยด้วย!
ฉันมีรายการทั่วไปสองรายการที่เต็มไปด้วย CustomsObjects
ฉันต้องการดึงความแตกต่างระหว่างสองรายการ (รายการที่อยู่ในรายการแรกโดยไม่มีรายการในรายการที่สอง) ในรายการที่สาม
ฉันคิดว่าการใช้.Except()เป็นความคิดที่ดี แต่ฉันไม่เห็นวิธีใช้นี้ .. ช่วยด้วย!
คำตอบ:
การใช้Exceptเป็นวิธีที่ถูกต้อง หากประเภทของคุณแทนที่EqualsและGetHashCodeหรือคุณสนใจเฉพาะความเท่าเทียมกันของประเภทการอ้างอิงเท่านั้น (กล่าวคือการอ้างอิงสองรายการจะ "เท่ากัน" หากอ้างอิงถึงวัตถุเดียวกันทั้งหมดเท่านั้น) คุณสามารถใช้:
var list3 = list1.Except(list2).ToList();
หากคุณต้องการที่จะแสดงความคิดที่กำหนดเองของความเท่าเทียมกันเช่นโดยใช้ ID, IEqualityComparer<T>คุณจะต้องดำเนินการ ตัวอย่างเช่น:
public class IdComparer : IEqualityComparer<CustomObject>
{
public int GetHashCode(CustomObject co)
{
if (co == null)
{
return 0;
}
return co.Id.GetHashCode();
}
public bool Equals(CustomObject x1, CustomObject x2)
{
if (object.ReferenceEquals(x1, x2))
{
return true;
}
if (object.ReferenceEquals(x1, null) ||
object.ReferenceEquals(x2, null))
{
return false;
}
return x1.Id == x2.Id;
}
}
จากนั้นใช้:
var list3 = list1.Except(list2, new IdComparer()).ToList();
โปรดทราบว่าสิ่งนี้จะลบองค์ประกอบที่ซ้ำกัน หากคุณต้องการเก็บรักษารายการที่ซ้ำกันไว้อาจเป็นเรื่องง่ายที่สุดในการสร้างชุดจากlist2และใช้สิ่งต่างๆเช่น:
var list3 = list1.Where(x => !set2.Contains(x)).ToList();
คุณสามารถทำสิ่งนี้:
var result = customlist.Where(p => !otherlist.Any(l => p.someproperty == l.someproperty));
Anyควรจะเป็นAllถ้าคุณต้องการที่จะทำเช่นนั้น เนื่องจากรายการที่สองอาจมีรายการจากรายการแรก แต่ถ้าไม่ใช่รายการแรกที่ตรวจสอบรายการนั้นจะได้รับจริงp.someproperty != l.somepropertyทันที ส่งผลให้มีการส่งคืนรายการที่มีอยู่ในทั้งสองรายการ สร้างความอับอายให้กับ 6 คนที่โหวตเรื่องนี้
ฉันคิดว่าสิ่งสำคัญที่ต้องเน้น - การใช้วิธียกเว้นจะส่งคืนสินค้าที่อยู่ในรายการแรกโดยไม่มีรายการในรายการที่สองเท่านั้น จะไม่ส่งคืนองค์ประกอบเหล่านั้นในวินาทีที่ไม่ปรากฏในครั้งแรก
var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };
var list3 = list1.Except(list2).ToList(); //list3 contains only 1, 2
แต่ถ้าคุณต้องการความแตกต่างที่แท้จริงระหว่างสองรายการ:
รายการที่อยู่ในรายการแรกโดยไม่มีรายการในรายการที่สองและรายการที่อยู่ในรายการที่สองโดยไม่มีรายการในรายการแรก
คุณต้องใช้ยกเว้นสองครั้ง:
var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };
var list3 = list1.Except(list2); //list3 contains only 1, 2
var list4 = list2.Except(list1); //list4 contains only 6, 7
var resultList = list3.Concat(list4).ToList(); //resultList contains 1, 2, 6, 7
หรือคุณสามารถใช้วิธีSymmetricExceptWithของ HashSet แต่มันเปลี่ยนชุดที่เรียกว่า:
var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };
var list1Set = list1.ToHashSet(); //.net framework 4.7.2 and .net core 2.0 and above otherwise new HashSet(list1)
list1Set.SymmetricExceptWith(list2);
var resultList = list1Set.ToList(); //resultList contains 1, 2, 6, 7
var third = first.Except(second);
(คุณสามารถโทรToList()ตามExcept()ได้หากคุณไม่ชอบอ้างอิงคอลเลกชันที่ขี้เกียจ)
Except()วิธีการเปรียบเทียบค่าใช้ Comparer เริ่มต้นถ้าค่าที่ถูกเปรียบเทียบเป็นประเภทฐานข้อมูลเช่นint, string, decimalฯลฯ
มิฉะนั้นจะทำการเปรียบเทียบโดยใช้ที่อยู่อ็อบเจ็กต์ซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ ... ในกรณีนั้นให้ใช้อ็อบเจ็กต์แบบกำหนดเองของคุณIComparable(หรือใช้แบบกำหนดเองIEqualityComparerและส่งต่อไปยังExcept()เมธอด)
var list3 = list1.Where(x => !list2.Any(z => z.Id == x.Id)).ToList();
หมายเหตุ: list3จะมีรายการหรือวัตถุที่ไม่อยู่ในทั้งสองรายการ หมายเหตุ: ToList()ไม่ใช่toList()
เนื่องจากวิธีการยกเว้นส่วนขยายทำงานบน IEumerables สองรายการสำหรับฉันแล้วดูเหมือนว่าจะเป็นการดำเนินการ O (n ^ 2) หากประสิทธิภาพเป็นปัญหา (หากบอกว่ารายการของคุณมีขนาดใหญ่) ฉันขอแนะนำให้สร้าง HashSet จาก list1 และใช้เมธอดยกเว้นของ HashSet
Enumerable.Exceptใช้ภายในHashSetหรือสิ่งที่คล้ายกัน แน่นอนว่ามันไม่ได้ใช้อัลกอริทึม O (n ^ 2) ที่ไร้เดียงสา
นี่คือทางออกของฉัน:
List<String> list1 = new List<String>();
List<String> list2 = new List<String>();
List<String> exceptValue = new List<String>();
foreach(String L1 in List1)
{
if(!List2.Contains(L1)
{
exceptValue.Add(L1);
}
}
foreach(String L2 in List2)
{
if(!List1.Contains(L2)
{
exceptValue.Add(L2);
}
}
สายไปหน่อย แต่นี่เป็นวิธีแก้ปัญหาสำหรับฉัน
var myBaseProperty = (typeof(BaseClass)).GetProperties();//get base code properties
var allProperty = entity.GetProperties()[0].DeclaringType.GetProperties();//get derived class property plus base code as it is derived from it
var declaredClassProperties = allProperty.Where(x => !myBaseProperty.Any(l => l.Name == x.Name)).ToList();//get the difference
ในโค้ดที่กล่าวถึงข้างต้นฉันได้รับความแตกต่างของคุณสมบัติระหว่างคลาสพื้นฐานและรายการคลาสที่ได้รับ
var resultList = checklist.Where(p => myList.All(l => p.value != l.value)).ToList();
List<ObjectC> _list_DF_BW_ANB = new List<ObjectC>();
List<ObjectA> _listA = new List<ObjectA>();
List<ObjectB> _listB = new List<ObjectB>();
foreach (var itemB in _listB )
{
var flat = 0;
foreach(var itemA in _listA )
{
if(itemA.ProductId==itemB.ProductId)
{
flat = 1;
break;
}
}
if (flat == 0)
{
_list_DF_BW_ANB.Add(itemB);
}
}
หากทั้งสองรายการของคุณใช้อินเทอร์เฟซ IEnumerable คุณสามารถทำได้โดยใช้ LINQ
list3 = list1.where(i => !list2.contains(i));
IEnumerable.Exceptแทน
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
List<int> listDifference = new List<int>();
foreach (var item1 in list1)
{
foreach (var item2 in list2)
{
if (item1 != item2)
listDifference.Add(item1);
}
}
Exceptเป็นการดำเนินการSetจากนั้นรายการผลลัพธ์จะมีค่าที่แตกต่างกันเช่น{'A','A','B','C'}.Except({'B','C'})ผลตอบแทน{'A'}