Wyraźne w Linq na podstawie tylko jednego pola tabeli


138

Próbuję użyć .distinct w Linq, aby uzyskać wynik na podstawie jednego pola tabeli (więc nie wymagają całego zduplikowanych rekordów z tabeli).

Wiem, jak pisać podstawowe zapytania, używając odrębnych:

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

ale potrzebuję wyników, które r.textnie są zduplikowane.


Musisz określić, które pole ma być odrębne, patrz msdn.microsoft.com/en-us/library/bb348436.aspx
— Antarr Byrd

Odpowiedzi:


308

Spróbuj tego:

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

Spowoduje to pogrupowanie tabeli według Texti użycie pierwszego wiersza z każdej grupy, co spowoduje utworzenie wierszy, w których Textjest inny.


2
A co jeśli Groupby ma więcej niż 1 pole?

6
@ user585440: W takim przypadku używasz typu anonimowego, takiego jak:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
— Daniel Hilgarth,

2
Tak, masz rację i już to znalazłem. W każdym razie dzięki. Uważam również, że Select (x => x.First ()) może powodować awarię. Lepiej jest zmienić na Select (x => x.FirstOrDefault ());

6
Musiałem użyć FirstOrDefault, bo inaczej wystąpił błąd wykonania
— TruthOf42

2
@ TruthOf42 To raczej mało prawdopodobne. GroupBynie tworzy pustych grup, zobacz mój poprzedni komentarz. Najprawdopodobniej twój kod zawiera więcej niż to, co tutaj widzisz. Może masz Whererównież lub warunek dla First.
— Daniel Hilgarth

26

MoreLinq ma metodę DistinctBy , której możesz użyć:

Pozwoli Ci to na:

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

Implementacja metody (bez walidacji argumentów) jest następująca:

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;
        }
    }
}

1
przepraszam, nie chciałem używać equalityComparer.
— Megha Jain

@MeghaJain Cóż, jeden będzie używany niezależnie, jak również GroupBypotrzebuje. Obie metody będą używać wartości domyślnej, EqualityComparerjeśli żadna nie zostanie podana.
— Servy

9
Cóż, popraw mnie, jeśli się mylę, ale to wyraźne tutaj jest zrobione w pamięci, a nie w DB? Czy to nie może doprowadzić do niepożądanego pełnego skanowania?
— Kek

@Kek. Nie, ze względu na zwrot z zysku zatrzymasz się na pierwszym odrębnym elemencie. Ostatecznie tak, załadujesz każdy klucz do HashSet, ale ponieważ jest on IEnumerable in i IEnumerable out, otrzymasz tylko te elementy. Jeśli mówisz o LINQ to SQL, to tak, spowoduje to skanowanie tabeli.
— PRMan

14

ale potrzebuję wyników, w których r.text nie jest zduplikowany

Brzmi, jakbyś tego chciała:

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

Spowoduje to wybranie wierszy, w których Textjest unikalny.


8

Powyższa odpowiedź Daniela Hilgartha prowadzi do System.NotSupportedwyjątku With Entity-Framework . W przypadku Entity-Framework musi to być:

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

3

Na ten temat toczy się wiele dyskusji.

Możesz znaleźć jeden z nich tutaj :

Jedną z najpopularniejszych sugestii jest metoda Distinct, przyjmująca wyrażenie lambda jako parametr, jak wskazał @Servy.

Główny architekt C #, Anders Hejlsberg, zaproponował tutaj rozwiązanie . Wyjaśnienie również, dlaczego zespół projektowy frameworka zdecydował się nie dodawać przeciążenia metody Distinct, która pobiera lambdę.


2

Z tego, co znalazłem, Twoje zapytanie jest w większości poprawne. Wystarczy zmienić „select r” na „select r.Text” i to powinno rozwiązać problem. W ten sposób MSDN udokumentowało, jak powinno działać.

Dawny:

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

zmieniliście polecenie „wybierz”, które może nie być pożądane w tym przypadku
— faza

1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });

-2

wypróbuj ten kod:

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

-6

Możesz spróbować tego:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.