Linq

2013-10-04 13 views
16

ile kesişen öğeden öğeleri kaldırın. Aynı özelliği paylaşan farklı nesnelerin 2 listesini (bar) id olarak adlandırıyorum.Linq

public List<foo> foo { get; set; } 
public List<bar> bar { get; set; } 

bu linq yapılabilir Nasıl bar

var olmayan bir kimliğe sahip foo tüm nesneleri kaldırmak istiyor ? Ben Intersect, RemoveAll & Join'a bakıyorum, ancak listelerin farklı türde olduğu herhangi bir örneği bulamıyorum.

cevap

23

bu deneyin: öğe bar koleksiyonunda ise

foo.RemoveAll(x=> !bar.Any(y=>y.Id==x.Id)); 

!bar.Any(y=>y.Id==x.Id) alacak ve onu değilse o foo koleksiyonundan kaldıracaktır.

(n)

daha iyi bir çözüm kullanılarak HashSet O: ikinci cevabın

var idsNotToBeRemoved = new HashSet<int>(bar.Select(item => item.Id));                      
foo.RemoveAll(item => !idsNotToBeRemoved.Contains(item.Id)); 

kaynağı https://stackoverflow.com/a/4037674/1714342

DÜZENLEME: @Carra bahsedilen olarak

, birinci çözelti küçük listeleri ve ikinci için iyidir büyük listeler için daha etkilidir.

+1

Brilliant @wudzik – ojhawkins

+2

Küçük listeler için ilk yapılacaklar. Büyük listeler (> 100 veya daha fazla) kullanıyorsanız, ikinci çözümü kullanmanız daha iyidir. – Carra

7
var foo = foo.Where(f => !bar.Any(b => b.Id == f.Id)).ToList(); 

Sadece bu bir O (n²) çözümü olduğunu akılda tutmak, bu büyük listeleri için çok iyi çalışmaz.

+0

Bunun için daha etkili bir çözüm ne olurdu? @Carra – ojhawkins

+0

@ojhawkins Bir çözüm, "id" lerinin listesini "hashset" e (O (n)) önceden toplamak ve daha sonra "foo" öğesindeki her öğeyi (O (n)) yerine karşılaştırmak olurdu. foo ' –

+0

'daki her öğe için' bar 'listesini yürümekten daha iyi görüyorum. Jon Skeets örneğini burada görebiliyordum ama bunu benim örneğime uygulayamadım http://stackoverflow.com/questions/853526/using-linq-to-remove -objects-bir-içinde-bir-liste içinde – ojhawkins