Używam LINQ do instrukcji Objects w uporządkowanej tablicy. Których operacji nie należy wykonywać, aby mieć pewność, że kolejność tablicy nie ulegnie zmianie?
Używam LINQ do instrukcji Objects w uporządkowanej tablicy. Których operacji nie należy wykonywać, aby mieć pewność, że kolejność tablicy nie ulegnie zmianie?
Odpowiedzi:
Zbadałem metody System.Linq.Enumerable , odrzucając wszystkie, które zwróciły wyniki niepoliczalne dla IE . Sprawdziłem uwagi każdego z nich, aby ustalić, w jaki sposób kolejność wyniku różni się od kolejności źródła.
Całkowicie zachowuje porządek. Możesz zamapować element źródłowy według indeksu na element wynikowy
Zachowuje porządek. Elementy są filtrowane lub dodawane, ale nie są ponownie zamawiane.
Niszczy zamówienie - nie wiemy, w jakiej kolejności można oczekiwać.
Wyraźnie redefiniuje kolejność - użyj ich, aby zmienić kolejność wyników
Przedefiniowuje porządek zgodnie z niektórymi zasadami.
Edycja: W oparciu o tę implementację przeniosłem Distinct na Zachowanie kolejności .
private static IEnumerable<TSource> DistinctIterator<TSource>
(IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource element in source)
if (set.Add(element)) yield return element;
}
Distinct
metody) miała po prostu powiedzieć „nieposortowane”, a nie „w nieprzewidywalnej kolejności”. Powiedziałbym, że Distinct
należy do powyższej kategorii filtrowania, podobnie jak Where
.
Czy faktycznie mówisz o SQL, czy o tablicach? Innymi słowy, czy używasz LINQ do SQL czy LINQ do Objects?
Operatorzy LINQ to Objects tak naprawdę nie zmieniają swojego oryginalnego źródła danych - budują sekwencje, które są skutecznie wspierane przez to źródło danych. Jedynymi operacjami, które zmieniają kolejność, są OrderBy / OrderByDescending / ThenBy / ThenByDescending - i nawet wtedy są stabilne dla równo uporządkowanych elementów. Oczywiście wiele operacji odfiltruje niektóre elementy, ale elementy, które zostaną zwrócone, będą w tej samej kolejności.
Jeśli przekonwertujesz na inną strukturę danych, np. Z ToLookup lub ToDictionary, nie sądzę, aby porządek został zachowany w tym momencie - ale i tak jest to nieco inne. (Wydaje mi się, że kolejność mapowania wartości na ten sam klucz jest zachowana dla wyszukiwania).
GroupBy
po nim SelectMany
podane zostaną wyniki pogrupowane według klucza, ale nie w rosnącej kolejności kluczy ... da to w kolejności, w której klucze wystąpiły pierwotnie.
list<x> {a b c d e f g}
przypadku, gdy wszystkie c, d, e mają ten sam klucz, wynikowa sekwencja będzie zawierać c, d, e obok siebie ORAZ w kolejności c, d, e. Nie mogę znaleźć kategorycznej odpowiedzi opartej na stwardnieniu rozsianym.
Jeśli pracujesz nad tablicą, wygląda na to, że używasz LINQ-to-Objects, a nie SQL; czy możesz potwierdzić? Większość operacji LINQ niczego nie porządkuje (dane wyjściowe będą w tej samej kolejności co dane wejściowe) - więc nie stosuj innego sortowania (OrderBy [Malejąco] / ThenBy [Malejąco]).
[edytuj: jak Jon uściślił; LINQ generalnie tworzy nową sekwencję, pozostawiając oryginalne dane w spokoju]
Zauważ, że wpychanie danych do Dictionary<,>
(ToDictionary) będzie szyfrować dane, ponieważ słownik nie przestrzega żadnej szczególnej kolejności sortowania.
Ale najczęstsze rzeczy (Wybierz, Gdzie, Pomiń, Weź) powinny być w porządku.
ToDictionary()
po prostu nie składa żadnych obietnic dotyczących kolejności, ale w praktyce utrzymuje kolejność wprowadzania (dopóki czegoś z niej nie usuniesz). Nie mówię, żebym na tym polegał, ale „mieszanie się” wydaje się niedokładne.
Znalazłem świetną odpowiedź w podobnym pytaniu, które odwołuje się do oficjalnej dokumentacji. Cytując to:
Dla Enumerable
metod (LINQ do obiektów, których dotyczy List<T>
), można polegać na zlecenie elementów zwróconych przez Select
, Where
lub GroupBy
. Nie dotyczy to rzeczy z natury nieuporządkowanych, takich jak ToDictionary
lub Distinct
.
Z dokumentacji Enumerable.GroupBy :
Te
IGrouping<TKey, TElement>
obiekty są uzyskane w kolejności na podstawie kolejności elementów w źródle, które produkowały pierwszy klucz każdegoIGrouping<TKey, TElement>
. Elementy w grupie są uzyskiwane w kolejności, w jakiej występująsource
.
Niekoniecznie dotyczy to IQueryable
metod rozszerzenia (inni dostawcy LINQ).
Źródło: Czy wyliczalne metody LINQ utrzymują względną kolejność elementów?
Pytanie tutaj odnosi się konkretnie do LINQ-to-Objects.
Jeśli zamiast tego używasz LINQ-to-SQL, nie ma tam żadnego zamówienia, chyba że narzucisz taki z czymś takim jak:
mysqlresult.OrderBy(e=>e.SomeColumn)
Jeśli nie zrobisz tego z LINQ-to-SQL, kolejność wyników może się różnić między kolejnymi zapytaniami, nawet tych samych danych, co może powodować przejściowy błąd.