LINQ ile siparişi koruma


Yanıtlar:


646

System.Linq.Enumerable yöntemlerini inceledim ve IEnumerable olmayan sonuçları döndüren herhangi birini atarak. Sonuç sırasının kaynağın sırasından nasıl farklı olacağını belirlemek için her birinin açıklamalarını kontrol ettim.

Siparişi Kesinlikle Korur. Bir kaynak öğeyi bir sonuç öğesine dizine göre eşleyebilirsiniz

  • AsEnumerable
  • Oyuncular
  • concat
  • seçmek
  • Sıralamak
  • Listeye

Düzeni Korur. Öğeler filtrelenir veya eklenir, ancak yeniden sipariş edilmez.

  • farklı
  • Dışında
  • Kesişim
  • OfType
  • Başa dön (.net 4.7.1'de yeni)
  • Atla
  • SkipWhile
  • almak
  • TakeWhile
  • Nerede
  • Zip (.net 4'te yeni)

Siparişi Yok Eder - sonuçların ne olacağını beklemiyoruz.

  • ToDictionary
  • ToLookup

Siparişi Açıkça Yeniden Tanımlar - sonucun sırasını değiştirmek için bunları kullanın

  • Tarafından sipariş
  • OrderByDescending
  • Tersine çevirmek
  • ThenBy
  • ThenByDescending

Düzeni bazı kurallara göre yeniden tanımlar.

  • GroupBy - IGrouping nesneleri, her IGrouping'in ilk anahtarını üreten kaynaktaki öğelerin sırasına göre bir sırada verilir. Bir gruplamadaki elemanlar, kaynakta göründükleri sırayla verilir.
  • GroupJoin - GroupJoin dış elemanların sırasını ve her dış eleman için eşleşen elemanların içten sırasını korur.
  • Birleştir - dış öğelerin sırasını ve bu öğelerin her biri için içteki eşleşen öğelerin sırasını korur.
  • SelectMany - kaynağın her bir elemanı için seçici çağrılır ve bir dizi değer döndürülür.
  • Birleşim - Bu yöntemle döndürülen nesne numaralandırıldığında, Birlik bu sırayla birinci ve ikinci olarak numaralandırır ve henüz verilmemiş her öğeyi verir.

Düzenleme: Bu uygulamaya dayalı Farklı Koruma siparişine taşındı .

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

2
Aslında, Distinct orijinal (ilk bulunan) düzeni koruyor - bu yüzden {1,2,1,3,1,3,4,1,5} {1,2,3,4,5} olur
Marc Gravell

10
msdn.microsoft.com/en-us/library/bb348436.aspx Fark <(Of <(TSource>)>) (IEnumerable <(Of <(TSource>)>)) yöntemi, yinelenen değer içermeyen sıralanmamış bir sıra döndürür .
Amy B

12
Marc: Söylediklerin doğru olabilir, ama bu davranışa güvenmek kötü bir fikir olurdu.
Amy B

4
@Amy B evet ama Linq to Objects için geçerli değil. Linq to Sql'de, farklı () öğesi, anahtar kelimeyi oluşturulan sql'ye koyar ve sql'den sipariş verilmesi garanti edilmez. Düzeni koruyan ve düzeni koruyan nesnelere linq için farklı bir uygulama görmek isterim. Örneğin, tüm girdiyi tüketebilir ve bir karma kümesine koyabilir, ardından karma kümesini (sıralama sırasını) numaralandırarak değerler verebilir, ancak bu daha kötüdür. Yani evet, her seferinde belgelere meydan okumayı önemsemiyorum :)
dan

4
Belki de dokümantasyon ( Distinctyöntem için) "öngörülemeyen sırada" değil, "sıralanmamış" demekti. DistinctAynen yukarıdaki filtreleme kategorisine ait olduğunu söyleyebilirim Where.
Jeppe Stig Nielsen

34

Aslında SQL'den mi yoksa dizilerden mi bahsediyorsunuz? Başka bir deyişle, LINQ to SQL veya LINQ to Objects kullanıyor musunuz?

LINQ to Objects operatörleri aslında orijinal veri kaynaklarını değiştirmez; veri kaynağı tarafından etkin bir şekilde desteklenen diziler oluştururlar. Sıralamayı değiştiren tek işlemler OrderBy / OrderByDescending / ThenBy / ThenByDescending şeklindedir - ve o zaman bile eşit olarak düzenlenmiş elemanlar için kararlıdır. Tabii ki, birçok işlem bazı öğeleri filtreleyecektir, ancak döndürülen öğeler aynı sırayla olacaktır.

Farklı bir veri yapısına dönüştürürseniz, örneğin ToLookup veya ToDictionary ile, siparişin bu noktada korunduğuna inanmıyorum - ama yine de biraz farklı. (Aynı anahtarla eşleştirilen değerlerin sırası, aramalar için korunur, ancak inanıyorum.)


OrderBy kararlı bir sıralama olduğundan, o zaman: seq.OrderBy (_ => _.Key) öğeleri seq.GroupBy (_ => _.Key) ile tam olarak aynı sıraya koyacaktır. ). Bu doğru mu?
dmg

1
@dmg: Hayır, olmayacak. Daha GroupBysonra SelectManysonuçları anahtarla gruplandırılmış olarak verir, ancak artan anahtar düzeninde vermez ... onları anahtarların başlangıçta gerçekleştiği sırayla verecektir.
Jon Skeet

LINQ to SQL koruyucu siparişi vermiyor musunuz?
symbiont

@symbiont: pek çok SQL operasyonlarda olduğu ile başlamak için hiçbir iyi tanımlanmış düzeni. Temelde sadece garanti edebileceğim şeyler hakkında sözler vermeye çalışıyorum - LINQ to Objects gibi.
Jon Skeet

@JonSkeet Eğer OrderBy kullanırsam, aynı tuşa sahip 'n' nesnelerinin bir arada olmaları dışında orijinal dizilerini koruyacaklarını garanti eder. yani: list<x> {a b c d e f g}c, d, e'nin hepsi aynı anahtara sahipse, sonuçta ortaya çıkan dizi, c, d, e sırasıyla AND, yan yana AND, c, d, e içerecektir. Kategorik MS tabanlı bir cevap bulamıyorum.
Paulustrious

7

Bir dizi üzerinde çalışıyorsanız, SQL yerine LINQ-to-Objects kullandığınız anlaşılıyor; onaylayabilir misin Çoğu LINQ işlemi hiçbir şeyi yeniden sıralamaz (çıktı girdiyle aynı sırada olur) - başka bir sıralama uygulamayın (OrderBy [Azalan] / ThenBy [Azalan]].

Jon daha açık bir şekilde ifade ettiği gibi; LINQ genellikle orijinal verileri yalnız bırakarak yeni bir dizi oluşturur ]

Verilerin bir Dictionary<,>(ToDictionary) içine itilmesinin, sözlüğün belirli bir sıralama düzenine uymadığından verilerin karıştırılacağını unutmayın.

Ancak en yaygın olan şeyler (Seç, Nerede, Atla, Al) iyi olmalıdır.


Yanılmıyorsam, ToDictionary()sadece sipariş hakkında hiçbir söz vermez , ancak pratikte giriş emrini korur (siz ondan bir şey kaldırana kadar). Buna güvenmiyorum demiyorum, ama 'karıştırmak' yanlış görünüyor.
Timo

4

Benzer bir soruda resmi belgelere gönderme yapan harika bir cevap buldum. Alıntı yapmak için:

İçin Enumerableyöntemleri (geçerli nesneleri için LINQ List<T>) kullanarak, dönen elemanların sırasında güvenebilir Select, Whereya da GroupBy. Bu doğası gereği gibi sırasız olan şeyler için durum böyle değildir ToDictionaryya Distinct.

Gönderen Enumerable.GroupBy belgelerinde:

IGrouping<TKey, TElement>Nesneleri her birinci anahtar üretilen kaynak öğeleri sırasına göre bir düzen içinde elde edilmektedir IGrouping<TKey, TElement>. Bir gruplamadaki öğeler göründükleri sıraya göre verilir source.

Bu, IQueryablegenişletme yöntemleri (diğer LINQ sağlayıcıları) için geçerli değildir .

Kaynak: LINQ'nun Numaralandırılabilir Yöntemleri, Elemanların Göreli Sırasını Koruyor mu?


2

Herhangi bir 'gruplama ölçütü' veya 'sıralama ölçütü' siparişi büyük olasılıkla değiştirecektir.


0

Buradaki soru özellikle LINQ-to-Objects anlamına gelmektedir.

Eğer LINQ-to-SQL kullanıyorsan, bunun gibi bir şey empoze etmedikçe, orada herhangi bir sipariş yoktur:

mysqlresult.OrderBy(e=>e.SomeColumn)

Bunu LINQ-to-SQL ile yapmazsanız, sonuçların sırası, aynı verilerden sonra bile gelen sorgular arasında değişebilir ve bu da aralıklı bir hataya neden olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.