Distinct() de LINQ en una propiedad particular
Estoy jugando con LINQ para aprender sobre él, pero no sé cómo usarlo Distinct
cuando 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 Distinct
en List<TElement>
una o más propiedades del ?TElement
Ejemplo: si un objeto es Person
, con propiedad Id
. ¿Cómo puedo obtenerlos todos Person
y usarlos Distinct
con la propiedad Id
del objeto?
Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"
¿Cómo puedo conseguir justo Person1
y Person3
? ¿Es eso posible?
Si no es posible con LINQ, ¿cuál sería la mejor manera de tener una lista Person
dependiendo de algunas de sus propiedades?
¿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
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 Id
propiedad, 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 HashSet
constructor.
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 where
ayuda a filtrar las entradas (podría ser más complejo) y a groupby
realizar select
la función distinta.
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();
Creo que es suficiente:
list.Select(s => s.MyField).Distinct();