Usa LINQ per ottenere elementi in un elenco , che non sono in un altro elenco

Presumo che ci sia una semplice query LINQ per fare questo, non sono esattamente sicuro di come. Si prega di vedere lo snippet di codice qui sotto.

class Program { static void Main(string[] args) { List peopleList1 = new List(); peopleList1.Add(new Person() { ID = 1 }); peopleList1.Add(new Person() { ID = 2 }); peopleList1.Add(new Person() { ID = 3 }); List peopleList2 = new List(); peopleList2.Add(new Person() { ID = 1 }); peopleList2.Add(new Person() { ID = 2 }); peopleList2.Add(new Person() { ID = 3 }); peopleList2.Add(new Person() { ID = 4 }); peopleList2.Add(new Person() { ID = 5 }); } } class Person { public int ID { get; set; } } 

Vorrei eseguire una query LINQ per darmi tutte le persone in peopleList2 che non sono in peopleList1 questo esempio dovrebbe darmi due persone (ID = 4 e ID = 5)

 var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID)); 

Se ignori l’uguaglianza delle persone, puoi anche utilizzare:

 peopleList2.Except(peopleList1) 

Except dovrebbe essere significativamente più veloce della variante Where(...Any) quanto può mettere la seconda lista in una tabella hash. Where(...Any) ha un runtime di O(peopleList1.Count * peopleList2.Count) mentre le varianti basate su HashSet quasi HashSet hanno un runtime di O(peopleList1.Count + peopleList2.Count) .

Except rimuove implicitamente i duplicati. Ciò non dovrebbe influenzare il tuo caso, ma potrebbe essere un problema per casi simili.

O se vuoi un codice veloce ma non vuoi sovrascrivere l’uguaglianza:

 var excludedIDs = new HashSet(peopleList1.Select(p => p.ID)); var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID)); 

Questa variante non rimuove i duplicati.

O se lo vuoi senza negazione:

 var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID)); 

Fondamentalmente dice di ottenere tutto da peopleList2 dove tutti gli id ​​di PeopleList1 sono diversi da id in peoplesList2.

Solo un approccio leggermente diverso dalla risposta accettata 🙂

Poiché tutte le soluzioni fino ad oggi hanno utilizzato la syntax fluente, ecco una soluzione nella syntax delle espressioni di query, per coloro che sono interessati:

 var peopleDifference = from person2 in peopleList2 where !( from person1 in peopleList1 select person1.ID ).Contains(person2.ID) select person2; 

Penso che sia abbastanza diverso dalle risposte date per essere di interesse per alcuni, anche se penso che molto probabilmente sarebbe subottimale per le Liste. Ora per le tabelle con ID indicizzati, questa sarebbe sicuramente la strada da percorrere.

Un po ‘tardi per la festa, ma una buona soluzione che è anche compatibile con Linq per SQL è:

 List list1 = new List() { "1", "2", "3" }; List list2 = new List() { "2", "4" }; List inList1ButNotList2 = (from o in list1 join p in list2 on o equals p into t from od in t.DefaultIfEmpty() where od == null select o).ToList(); List inList2ButNotList1 = (from o in list2 join p in list1 on o equals p into t from od in t.DefaultIfEmpty() where od == null select o).ToList(); List inBoth = (from o in list1 join p in list2 on o equals p into t from od in t.DefaultIfEmpty() where od != null select od).ToList(); 

Complimenti a http://www.dotnet-tricks.com/Tutorial/linq/UXPF181012-SQL-Joins-with-C

La risposta di Klaus è stata ottima, ma ReSharper ti chiederà di “Semplificare l’espressione LINQ”:

var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));

Questa estensione enumerabile consente di definire un elenco di elementi da escludere e una funzione da utilizzare per trovare la chiave da utilizzare per eseguire il confronto.

 public static class EnumerableExtensions { public static IEnumerable Exclude(this IEnumerable source, IEnumerable exclude, Func keySelector) { var excludedSet = new HashSet(exclude.Select(keySelector)); return source.Where(item => !excludedSet.Contains(keySelector(item))); } } 

Puoi usarlo in questo modo

 list1.Exclude(list2, i => i.ID); 

Ecco un esempio funzionante che acquisisce competenze IT che un candidato non ha già.

 //Get a list of skills from the Skill table IEnumerable skillenum = skillrepository.Skill; //Get a list of skills the candidate has IEnumerable candskillenum = candskillrepository.CandSkill .Where(p => p.Candidate_ID == Candidate_ID); //Using the enum lists with LINQ filter out the skills not in the candidate skill list IEnumerable skillenumresult = skillenum.Where(p => !candskillenum.Any(p2 => p2.Skill_ID == p.Skill_ID)); //Assign the selectable list to a viewBag ViewBag.SelSkills = new SelectList(skillenumresult, "Skill_ID", "Skill_Name", 1);