Distintivo en Linq basado en un solo campo de la tabla

133

Estoy tratando de usar .distinct en Linq para obtener resultados basados ​​en un campo de la tabla (por lo que no requieren registros duplicados completos de la tabla).

Sé escribir una consulta básica usando distinto de la siguiente manera:

var query = (from r in table1
orderby r.Text
select r).distinct();

pero necesito resultados donde r.textno está duplicado.

Megha Jain
fuente
Debe

Respuestas:

300

Prueba esto:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

Esto agrupará la tabla Texty usará la primera fila de cada grupo, lo que dará como resultado filas donde Textes diferente.

Daniel Hilgarth
fuente
2
¿Qué pasa si groupby tiene más de 1 campo?
66
@ user585440: En ese caso, utiliza un tipo anónimo como este:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth
2
Sí, tienes razón y ya lo encontré. Gracias de cualquier manera. Y también encuentro que Select (x => x.First ()) puede causar un bloqueo. Es mejor cambiar a Select (x => x.FirstOrDefault ());
66
Tuve que usar FirstOrDefault o de lo contrario hubo un error de tiempo de ejecución
TruthOf42
2
@ TruthOf42 Eso es bastante improbable. GroupByno crea grupos vacíos, mira mi comentario anterior. Lo más probable es que su código contenga más de lo que ve aquí. Tal vez usted también tiene Whereo una condición para el First.
Daniel Hilgarth
26

MoreLinq tiene un método DistinctBy que puede usar:

Te permitirá hacer:

var results = table1.DistictBy(row => row.Text);

La implementación del método (sin validación de argumento) es la siguiente:

private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
    HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
    foreach (TSource element in source)
    {
        if (knownKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}
Servy
fuente
lo siento, no estaba interesado en utilizar equalComparer.
Megha Jain
@MeghaJain Bueno, uno se usará independientemente, ya que también GroupBynecesita uno. Ambos métodos usarán el predeterminado EqualityComparersi no se proporciona ninguno.
Servicio
9
Bueno, corrígeme si estoy equivocado, pero esto se hace aquí en memoria, no en DB. ¿No podría esto conducir a un escaneo completo no deseado?
Kek
@Kek. No, debido al rendimiento, se detendrá en el primer elemento distinto. Eventualmente, sí, cargará cada clave en el HashSet, pero como es IEnumerable in y IEnumerable out, solo obtendrá esos elementos. Si está hablando de LINQ to SQL, entonces sí, esto hará un escaneo de tabla.
PRMan
12

pero necesito resultados donde r.text no está duplicado

Suena como si quisieras esto:

table1.GroupBy(x => x.Text)
      .Where(g => g.Count() == 1)
      .Select(g => g.First());

Esto seleccionará filas donde el Textes único.

Tim Schmelter
fuente
7

La respuesta de Daniel Hilgarth anterior lleva a una System.NotSupportedexcepción con Entity-Framework . Con Entity-Framework , tiene que ser:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());
Biraj Saha
fuente
3

Hay muchas discusiones sobre este tema.

Puedes encontrar uno de ellos aquí :

Una de las sugerencias más populares ha sido el método Distinct que toma una expresión lambda como parámetro, como ha señalado @Servy.

El arquitecto jefe de C #, Anders Hejlsberg ha sugerido la solución aquí . También explicando por qué el equipo de diseño del marco decidió no agregar una sobrecarga del método Distinct que toma una lambda.

TKharaishvili
fuente
2

Por lo que he encontrado, su consulta es en su mayoría correcta. Simplemente cambie "select r" a "select r.Text" es todo y eso debería resolver el problema. Así es como MSDN documentó cómo debería funcionar.

Ex:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();
Josh Parks
fuente
usted cambió la declaración "select" que puede no ser deseada en este caso
faza
1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });
bgS
fuente
-2

prueba este código:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());
HamidReza
fuente
-5

Puedes probar esto:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

LucaGuerra
fuente