Utilice LINQ para obtener elementos en una lista<>, que no están en otra Lista<>


Asumiría que hay una simple consulta LINQ para hacer esto, simplemente no estoy exactamente seguro de cómo. Consulte el fragmento de código a continuación.

class Program
{
    static void Main(string[] args)
    {
        List<Person> peopleList1 = new List<Person>();
        peopleList1.Add(new Person() { ID = 1 });
        peopleList1.Add(new Person() { ID = 2 });
        peopleList1.Add(new Person() { ID = 3 });

        List<Person> peopleList2 = new List<Person>();
        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; }
}

Me gustaría realizar una consulta LINQ para darme todas las personas en peopleList2 que no están en peopleList1 este ejemplo debería darme dos personas (ID = 4 & ID = 5)

Author: ᴍᴀᴛᴛ ʙᴀᴋᴇʀ, 2010-10-15

8 answers

var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));
 691
Author: Klaus Byskov Pedersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-15 18:02:06

Si anula la igualdad de las personas, también puede usar:

peopleList2.Except(peopleList1)

Except debería ser significativamente más rápido que la variante Where(...Any) ya que puede poner la segunda lista en una tabla hash. Where(...Any) tiene un tiempo de ejecución de O(peopleList1.Count * peopleList2.Count) mientras que las variantes basadas en HashSet<T> (casi) tienen un tiempo de ejecución de O(peopleList1.Count + peopleList2.Count).

Except elimina implícitamente los duplicados. Eso no debería afectar su caso, pero podría ser un problema para casos similares.

O si desea código rápido pero no desea anular la igualdad:

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

Esta variante no elimina duplicados.

 296
Author: CodesInChaos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-17 11:51:07

O si lo quieres sin negación:

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

Básicamente dice obtener todo de peopleList2 donde todos los id en peopleList1 son diferentes de id en peoplesList2.

Solo un enfoque un poco diferente de la respuesta aceptada:)

 46
Author: user1271080,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-21 12:38:22

Dado que todas las soluciones hasta la fecha utilizan sintaxis fluida, aquí hay una solución en sintaxis de expresión de consulta, para aquellos interesados:

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

Creo que es lo suficientemente diferente de las respuestas dadas para ser de interés para algunos, incluso aunque lo más probable sería subóptimo para las Listas. Ahora, para las tablas con IDS indexados, este sería definitivamente el camino a seguir.

 28
Author: Michael Goldshteyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-16 22:16:38

Un poco tarde para el partido, pero una buena solución que también es compatible con Linq a SQL es:

List<string> list1 = new List<string>() { "1", "2", "3" };
List<string> list2 = new List<string>() { "2", "4" };

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

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

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

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

 12
Author: Richard Ockerby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-19 11:27:35

La respuesta de Klaus fue genial, pero ReSharper te pedirá que "Simplifiques la expresión LINQ":

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

 6
Author: Brian T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-16 23:42:30

Esta Extensión enumerable le permite definir una lista de elementos a excluir y una función a utilizar para encontrar la clave a utilizar para realizar la comparación.

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

Puedes usarlo de esta manera

list1.Exclude(list2, i => i.ID);
 4
Author: Bertrand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-08 10:10:24

Aquí hay un ejemplo de trabajo que obtiene habilidades de TI que un candidato de trabajo no ya tienen.

//Get a list of skills from the Skill table
IEnumerable<Skill> skillenum = skillrepository.Skill;
//Get a list of skills the candidate has                   
IEnumerable<CandSkill> 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<Skill> 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);
 0
Author: Brian Quinn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-16 20:52:46