Başka bir listedeki öğeleri kaldırma


206

Başka bir öğe listesinden kaldırmak istediğiniz öğelerin genel bir listesini geçmek için nasıl anlamaya çalışıyorum.

Diyelim ki buna varsayımsal bir örnek var

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

List1'i bir foreach ile çaprazlamak ve List1'de de List2'de bulunan her öğeyi kaldırmak istiyorum.

Foreach dizin tabanlı olmadığı için bu konuda nasıl emin değilim.


1
List1'deki List2'deki öğeleri kaldırmak istiyor musunuz?
Srinivas Reddy Thatiparthy

1
List1 = {foo1} ve list2 = {foo1, foo1} varsa ne olur? Foo1'in tüm kopyaları liste2'den mi yoksa sadece ilkinden mi çıkarılmalıdır?
Mark Byers

2
-1 - Bu sorunun her cevabını reddettim çünkü hepsinin yanlış olduğunu düşündüm , ancak soru sadece korkunç bir şekilde soruluyor gibi görünüyor. Şimdi onları değiştiremem - özür dilerim. Eğer öğeleri kaldırmak istiyor musunuz list1o varoldukları için list2veya öğeleri kaldırmak istiyorsunuz list2o varoldukları için list1? Bu yorum sırasında, verilen her cevap bu ikinciyi cevaplar.
John Rasch

7
John Rashch, bu aşağı oylarda biraz daha az tetikleyici olmalısın. Bazı cevaplar oldukça kavramsaldır ve yalnızca OP'nin istediği şeyleri söz konusu listelerle ilişkilendirmeden bile nasıl elde edeceğini gösterir.
João Angelo

3
@ Mark - haklısın, tamamen benim hatam - bu yüzden ne olduğunu açıklayan yorumu buraya koydum, oylamadan sonra benzer bir soruya daha önce sahip olduğum bir cevabı arıyordum ve ayrılacaktım Ben buldum sonra yorum - bunun için en iyi süreç olmadığı ortaya çıkıyor!
John Rasch

Yanıtlar:


358

Şunlar dışında kullanabilirsiniz :

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

Muhtemelen şu geçici değişkenlere bile ihtiyacınız yoktur:

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

Not ExceptHer iki listeyi değiştirmez - bu sonuçla yeni bir liste oluşturur.


13
Küçük nokta, ama bu bir üretecek IEnumerable<car>, değil List<car>. ToList()Bir listeyi geri almak için aramalısınız . Buna ek olarak, olması gerektiğine inanıyorumGetSomeOtherList().Except(GetTheList()).ToList()
Adam Robinson

9
Daha using System.Linq;önce sahip değilseniz da ihtiyacınız olacak .
yellavon

1
Not: list1.Except (list2), list2.Except (list1) ile aynı sonucu vermez. Sonuncusu benim için çalıştı.
radbyx

2
ExceptBu , sonuçta ortaya çıkan listeyi ayıran belirli bir işlem gerçekleştirdiğinden , kullanırken dikkatli olun . Ben kullanıyorum ben bu davranışı beklemiyordum List, bir değil HashSet. İlişkili.
Logan

4
Bu nasıl doğru cevap? Elbette, bu size bağlamınızda ne istediğinizi verebilir, ancak, "Başka bir listedeki öğeleri kaldır" kesinlikle ayarlanmış bir fark işlemine eşdeğer değildir ve bunu doğru cevap olarak kabul ederek insanları yanlış bilgilendirmemelisiniz !!!!
user1935724

37

List<T>Sınıf, Removeişlevi kullanarak dizin yerine öğeleri değere göre kaldırmanıza izin verdiği için bir dizine ihtiyacınız yoktur .

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

3
+1, ancak IMO list2.Remove(item);deyim çevresinde parantez kullanmalısınız .
ANeves

2
@sr pt: Her zaman başka bir satırda görünen ifadelerde parantez kullanırım, ancak akış denetim ifadesiyle aynı satıra yerleştirebileceğim / yapabileceğim tek ifadeli bloklarda değil.
Adam Robinson

4
@uriz: Zarif olanın niteliklerini göz ardı ederek, sorunun gerçekten söylediği şeyi yapan tek cevap budur (ana listedeki öğeleri kaldırır); diğer cevap, yeni bir liste oluşturur ve bu liste, yeni bir liste almak yerine değiştirilmeyi bekleyen farklı bir arayandan aktarılırsa istenmeyebilir.
Adam Robinson

5
@uriz @AdamRobinson zarif çözümler tartıştığımızdan beri ...list1.ForEach(c => list2.Remove(c));
David Sherret

1
"zarif" anlamına gelir "bu kodu korumak sıkışmış geliştirici basit ve anlaşılması kolay bulacaksınız", bu yüzden bu en iyi cevaptır.
Seth

22

LINQ genişletme yöntemlerini kullanmanızı tavsiye ederim . Bunu böyle bir kod satırı ile kolayca yapabilirsiniz:

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

Bu, elbette list1'deki list2'den kaldırdığınız nesnelerin aynı örnek olduğunu varsayar.


2
Yinelemeleri de kaldırır.
TemmuzOrdinary

17

Benim durumumda, ortak bir tanımlayıcıyla, yabancı bir anahtar gibi iki farklı listem vardı. "Nzrytmn" tarafından belirtilen ikinci çözüm :

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

Benim durumuma en uygun olanıydı. Önceden kaydedilmiş kayıtlar olmadan bir DropDownList yüklemem gerekiyordu.

Teşekkür ederim !!!

Bu benim kodum:

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();

ou DDlT3'ün ne olduğunu hiç açıklamadı
rogue39nin

15

LINQ kullanabilirsiniz, ama RemoveAllyöntem ile gitmek istiyorum . Bence niyetinizi daha iyi ifade eden bu.

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
Veya yöntem grupları ile daha da basit yapabilirsiniz - integers.RemoveAll (remove.Contains);
Ryan

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

aka "tamamen saf" :-)
Xan-Kun Clark-Davis

Bunda yanlış olan ne. Hariç Tut'u kullanarak başka bir liste oluşturmaktan daha iyi görünüyor. Özellikle her iki liste de çok küçük olduğunda.
Mike Keskinov

1
Her iki liste yöntemi de olduğundan O(N), bu O(N^2)büyük listelerde bir sorun olabilir.
tigrou

7

Çözüm 1: Bunu şöyle yapabilirsiniz:

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

Ancak bazı durumlarda bu çözüm işe yaramayabilir. eğer işe yaramazsa ikinci çözümümü kullanabilirsiniz.

Çözüm 2:

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

list1'in ana listeniz olduğunu ve list2'nin ikinci listeniz olduğunu ve list2 öğelerini liste2 öğeleri olmadan almak istediğinizi varsayalım.

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

0

As Exceptlistesinde değişiklik yok, sen kullanabilirsiniz ForEach üzerinde List<T>:

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

En etkili yol olmayabilir, ancak basit, bu nedenle okunabilir ve orijinal listeyi günceller (bu benim gereksinimimdir).


-3

Buyrun ..

    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. Bu, ilk öğe kaldırıldıktan sonra bir istisna atar. Ayrıca, genellikle küçük olduğundan listeyi kaldırmak için (genellikle) daha iyi bir fikirdir . Ayrıca bu şekilde daha fazla liste geçişi yapmaya zorluyorsunuz.
Adam Robinson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.