Distinct() de LINQ en una propiedad particular

Resuelto Patrick Desjardins asked hace 15 años • 23 respuestas

Estoy jugando con LINQ para aprender sobre él, pero no sé cómo usarlo Distinctcuando no tengo una lista simple (una lista simple de números enteros es bastante fácil de hacer, esa no es la cuestión). ¿ Qué hago si quiero usar Distincten List<TElement>una o más propiedades del ?TElement

Ejemplo: si un objeto es Person, con propiedad Id. ¿Cómo puedo obtenerlos todos Persony usarlos Distinctcon la propiedad Iddel objeto?

Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"

¿Cómo puedo conseguir justo Person1y Person3? ¿Es eso posible?

Si no es posible con LINQ, ¿cuál sería la mejor manera de tener una lista Persondependiendo de algunas de sus propiedades?

Patrick Desjardins avatar Jan 29 '09 03:01 Patrick Desjardins
Aceptado

¿Qué pasa si quiero obtener una lista distinta basada en una o más propiedades?

¡Simple! Quieres agruparlos y elegir un ganador del grupo.

List<Person> distinctPeople = allPeople
  .GroupBy(p => p.PersonId)
  .Select(g => g.First())
  .ToList();

Si desea definir grupos en varias propiedades, aquí le explicamos cómo:

List<Person> distinctPeople = allPeople
  .GroupBy(p => new {p.PersonId, p.FavoriteColor} )
  .Select(g => g.First())
  .ToList();

Nota: Ciertos proveedores de consultas no pueden resolver que cada grupo debe tener al menos un elemento y que First es el método apropiado para llamar en esa situación. Si se encuentra trabajando con un proveedor de consultas de este tipo, FirstOrDefault puede ayudarlo a realizar su consulta a través del proveedor de consultas.

Nota 2: Considere esta respuesta para un enfoque compatible con EF Core (anterior a EF Core 6). https://stackoverflow.com/a/66529949/8155

Amy B avatar Jan 29 '2009 14:01 Amy B

EDITAR : Esto ahora es parte de MoreLINQ .

Lo que necesita es una "distinción por" eficaz. No creo que sea parte de LINQ tal como está, aunque es bastante fácil de escribir:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (seenKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

Entonces, para encontrar los valores distintos usando solo la Idpropiedad, puedes usar:

var query = people.DistinctBy(p => p.Id);

Y para usar múltiples propiedades, puedes usar tipos anónimos, que implementan la igualdad de manera apropiada:

var query = people.DistinctBy(p => new { p.Id, p.Name });

No probado, pero debería funcionar (y ahora al menos se compila).

Sin embargo, asume el comparador predeterminado para las claves: si desea pasar un comparador de igualdad, simplemente páselo al HashSetconstructor.

Jon Skeet avatar Jan 28 '2009 21:01 Jon Skeet

Usar:

List<Person> pList = new List<Person>();
/* Fill list */

var result = pList.Where(p => p.Name != null).GroupBy(p => p.Id)
    .Select(grp => grp.FirstOrDefault());

Le whereayuda a filtrar las entradas (podría ser más complejo) y a groupbyrealizar selectla función distinta.

karcsi avatar Feb 14 '2012 12:02 karcsi

También puedes usar la sintaxis de consulta si quieres que se vea como LINQ:

var uniquePeople = from p in people
                   group p by new {p.ID} //or group by new {p.ID, p.Name, p.Whatever}
                   into mygroup
                   select mygroup.FirstOrDefault();
Chuck Rostance avatar Mar 06 '2012 18:03 Chuck Rostance

Creo que es suficiente:

list.Select(s => s.MyField).Distinct();
Ivan avatar Jan 23 '2015 14:01 Ivan