ลบรายการออกจากรายการหนึ่งในรายการอื่น


206

ฉันกำลังพยายามหาวิธีสำรวจรายการทั่วไปที่ฉันต้องการลบออกจากรายการอื่น

สมมุติว่าฉันมีนี่เป็นตัวอย่างสมมุติ

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();

ฉันต้องการสำรวจ list1 ด้วย foreach และลบแต่ละรายการใน List1 ซึ่งมีอยู่ใน List2 ด้วย

ฉันไม่แน่ใจว่าจะทำอย่างไรกับเรื่องนี้เนื่องจาก foreach ไม่ใช่ดัชนีตาม


1
คุณต้องการลบรายการใน List1 ซึ่งอยู่ใน List2 ด้วยหรือไม่
Srinivas Reddy Thatiparthy

1
จะเกิดอะไรขึ้นถ้าคุณมี list1 = {foo1} และ list2 = {foo1, foo1} ควรลบสำเนาทั้งหมดของ foo1 ออกจาก list2 หรือเฉพาะตอนแรก
Mark Byers

2
-1 - ฉันได้ลงคะแนนทุกคำตอบในคำถามนี้เพราะฉันคิดว่าพวกเขาผิดทั้งหมด แต่ดูเหมือนว่าคำถามจะถูกถามอย่างน่ากลัว ตอนนี้ฉันไม่สามารถเปลี่ยนได้ - ขอโทษ คุณต้องการที่จะลบรายการจากlist1ที่มีอยู่ในlist2หรือคุณต้องการที่จะลบรายการจากlist2ที่มีอยู่ในlist1? ในช่วงเวลาของความคิดเห็นนี้แต่ละคำตอบที่ให้ไว้จะดำเนินการอย่างหลัง
John Rasch

7
@John Rashch คุณน่าจะมีความสุขน้อย ๆ คำตอบบางข้อเป็นแนวคิดที่เป็นธรรมและแสดงให้เห็นว่าจะบรรลุสิ่งที่ OP ต้องการโดยไม่ต้องเกี่ยวข้องกับรายการที่กล่าวถึงในคำถาม
João Angelo

3
@ Mark - ถูกต้องความผิดของฉันทั้งหมด - นั่นเป็นเหตุผลที่ฉันใส่ความคิดเห็นไว้ที่นี่เพื่ออธิบายสิ่งที่เกิดขึ้นฉันกำลังค้นหาคำตอบก่อนหน้านี้ที่ฉันมีอยู่แล้วสำหรับคำถามที่คล้ายกันในระหว่างนี้หลังจากการลงคะแนนของฉัน ความคิดเห็นหลังจากที่ฉันพบ - ปรากฎว่าไม่ใช่กระบวนการที่ดีที่สุดสำหรับเรื่องนี้!
John Rasch

คำตอบ:


358

คุณสามารถใช้ยกเว้น :

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();
List<car> result = list2.Except(list1).ToList();

คุณอาจไม่ต้องการตัวแปรชั่วคราวเหล่านั้นด้วยซ้ำ:

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();

โปรดทราบว่าExceptจะไม่แก้ไขรายการใดรายการหนึ่ง - มันสร้างรายการใหม่พร้อมผลลัพธ์


13
จุดเล็ก ๆ น้อย ๆ แต่นี้จะผลิตไม่ได้IEnumerable<car> List<car>คุณต้องโทรหาToList()เพื่อรับรายการกลับ นอกจากนี้ฉันเชื่อว่าควรจะเป็นGetSomeOtherList().Except(GetTheList()).ToList()
อาดัมโรบินสัน

9
คุณจะต้องusing System.Linq;ถ้าคุณไม่เคยมีมาก่อน
yellavon

1
หมายเหตุ: list1.Except (list2) จะไม่ให้ผลลัพธ์เหมือนกับ list2.Except (list1) การทำงานครั้งสุดท้ายสำหรับฉัน
radbyx

2
โปรดใช้ความระมัดระวังเมื่อใช้Exceptเนื่องจากจะเป็นการดำเนินการชุดจริงซึ่งจะแยกรายการผลลัพธ์ ผมไม่ได้คาดหวังว่าพฤติกรรมนี้เป็นผมใช้ไม่ได้List ที่เกี่ยวข้อง HashSet
logan

4
นี่เป็นคำตอบที่ถูกต้องทำไม แน่ใจว่าสิ่งนี้อาจให้สิ่งที่คุณต้องการในบริบทของคุณอย่างไรก็ตาม "ลบรายการจากรายการหนึ่งในอีกรายการ" ไม่แน่นอนเท่ากับการดำเนินการที่แตกต่างกันและคุณไม่ควรตีความผิดคนโดยยอมรับว่านี่เป็นคำตอบที่ถูกต้อง !!!!
user1935724

37

คุณไม่ต้องการดรรชนีเนื่องจากList<T>คลาสอนุญาตให้คุณลบไอเท็มตามค่าแทนดรรชนีโดยใช้Removeฟังก์ชัน

foreach(car item in list1) list2.Remove(item);

3
+1 แต่ IMO คุณควรใช้วงเล็บรอบlist2.Remove(item);คำสั่ง
Aneves

2
@sr pt: ฉันมักจะใช้วงเล็บในงบที่ปรากฏในบรรทัดอื่น แต่ไม่ได้อยู่ในบล็อกคำสั่งเดียวที่ฉันสามารถ / ทำในบรรทัดเดียวกันเป็นคำสั่งควบคุมการไหล
อดัมโรบินสัน

4
@uriz: ไม่คำนึงถึงคุณสมบัติของสิ่งที่จะสง่างามนี้เป็นคำตอบเดียวที่จริง ๆ แล้วสิ่งที่คำถามพูด (ลบรายการในรายการหลัก); คำตอบอื่น ๆ จะสร้างรายการใหม่ซึ่งอาจไม่เป็นที่ต้องการหากรายชื่อนั้นถูกส่งผ่านจากผู้โทรรายอื่นที่คาดว่าจะได้รับการแก้ไขแทนที่จะได้รับรายชื่อการเปลี่ยนใหม่
อดัมโรบินสัน

5
@uriz @AdamRobinson ตั้งแต่ที่เรากำลังคุยกันเรื่องการแก้ปัญหาที่สง่างาม ...list1.ForEach(c => list2.Remove(c));
เดวิด Sherret

1
"ฉลาด" ควรหมายถึง "นักพัฒนาที่ติดตั้งรหัสนี้จะพบว่ามันง่ายและเข้าใจง่าย" ซึ่งเป็นเหตุผลที่นี่เป็นคำตอบที่ดีที่สุด
เซ

22

ฉันจะแนะนำให้ใช้วิธีการขยาย LINQ คุณสามารถทำได้อย่างง่ายดายด้วยโค้ดหนึ่งบรรทัดเช่น:

list2 = list2.Except(list1).ToList();

นี่เป็นการสมมติว่าวัตถุใน list1 ที่คุณลบออกจาก list2 นั้นเป็นอินสแตนซ์เดียวกัน


2
มันลบรายการที่ซ้ำกันเช่นกัน
กรกฎาคม

17

ในกรณีของฉันฉันมีสองรายการที่แตกต่างกันโดยมีตัวระบุร่วมกันเป็นเหมือนคีย์ต่างประเทศ วิธีที่สองอ้างถึงโดย"nzrytmn" :

var result =  list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();

เป็นคนที่เหมาะสมที่สุดในสถานการณ์ของฉัน ฉันต้องการโหลด DropDownList โดยไม่ต้องบันทึกที่ลงทะเบียนแล้ว

ขอบคุณ !!!

นี่คือรหัสของฉัน:

t1 = new T1();
t2 = new T2();

List<T1> list1 = t1.getList();
List<T2> list2 = t2.getList();

ddlT3.DataSource= list2.Where(s => !list1.Any(p => p.Id == s.ID)).ToList();
ddlT3.DataTextField = "AnyThing";
ddlT3.DataValueField = "IdAnyThing";
ddlT3.DataBind();

คุณไม่เคยอธิบายว่า DDlT3 คืออะไร
rogue39nin

15

คุณสามารถใช้ LINQ แต่ฉันจะไปด้วยRemoveAllวิธี ฉันคิดว่านั่นเป็นสิ่งที่แสดงออกถึงความตั้งใจของคุณได้ดีกว่า

var integers = new List<int> { 1, 2, 3, 4, 5 };

var remove = new List<int> { 1, 3, 5 };

integers.RemoveAll(i => remove.Contains(i));

9
หรือแม้แต่ง่ายขึ้นด้วยกลุ่มวิธีที่คุณสามารถทำได้ - จำนวนเต็มลบทั้งหมด (remove.Contains);
Ryan

12
list1.RemoveAll(l => list2.Contains(l));

อาคา "เต็มเปาไม่บริสุทธิ์" :-)
Xan-Kun คลาร์ก - เดวิส

เกิดอะไรขึ้นกับมัน มันดูดีขึ้นแล้วสร้างรายการอื่นโดยใช้ยกเว้น โดยเฉพาะอย่างยิ่งเมื่อรายการทั้งสองมีขนาดเล็กมาก
Mike Keskinov

1
เนื่องจากทั้งสองรายการวิธีO(N)นี้จะนำไปสู่O(N^2)ซึ่งอาจเป็นปัญหากับรายการขนาดใหญ่
tigrou

7

โซลูชันที่ 1: คุณสามารถทำสิ่งนี้:

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList();

แต่ในบางกรณีการแก้ปัญหานี้อาจไม่ทำงาน หากไม่ได้ผลคุณสามารถใช้โซลูชันที่สองของฉัน

โซลูชันที่ 2:

List<car> list1 = GetTheList();
List<car> list2 = GetSomeOtherList();

เราทำท่าว่า list1 เป็นรายการหลักของคุณและ list2 เป็นรายการอันดับสองของคุณและคุณต้องการรับรายการของ list1 โดยไม่มีรายการของ list2

 var result =  list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList();

0

เนื่องจากExceptไม่ได้แก้ไขรายการคุณสามารถใช้ForEachบนList<T>:

list2.ForEach(item => list1.Remove(item));

มันอาจไม่ใช่วิธีที่มีประสิทธิภาพที่สุด แต่ก็ง่ายอ่านง่ายและอัปเดตรายการดั้งเดิม (ซึ่งเป็นข้อกำหนดของฉัน)


-3

นี่ไงไปเลย ..

    List<string> list = new List<string>() { "1", "2", "3" };
    List<string> remove = new List<string>() { "2" };

    list.ForEach(s =>
        {
            if (remove.Contains(s))
            {
                list.Remove(s);
            }
        });

3
-1 การดำเนินการนี้จะทำให้เกิดข้อยกเว้นหลังจากลบรายการแรก นอกจากนี้ (โดยทั่วไป) เป็นความคิดที่ดีกว่าที่จะสำรวจรายการที่จะลบเนื่องจากมักจะมีขนาดเล็กลง นอกจากนี้คุณยังบังคับให้ผู้สำรวจเส้นทางรายการทำเช่นนี้อีก
อดัมโรบินสัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.