Her döngü için bir C # bir List <T> üzerinde hangi sırayla yinelenir?


84

C # 'daki foreach döngüsünün bir System.Collections.Generic.List<T>nesneden geçtiği sırayı merak ediyordum .

Aynı konuyla ilgili başka bir soru buldum , ancak sorumu tatmin edecek şekilde yanıtladığını düşünmüyorum.

Birisi hiçbir siparişin tanımlanmadığını belirtiyor. Ancak başka birinin de belirttiği gibi, bir diziyi geçme sırası sabittir (0'dan Uzunluk-1'e). 8.8.4 foreach ifadesi

Aynı durumun, bir siparişe sahip herhangi bir standart sınıf için de geçerli olduğu söylendi (örneğin List<T>). Bunu yedekleyecek herhangi bir belge bulamıyorum. Yani, bildiğim kadarıyla, şimdi böyle çalışabilir, ancak belki bir sonraki .NET sürümünde farklı olacaktır (olası olmasa da).

List(t).EnumeratorBelgelere de şanssız baktım .

İlgili başka bir soru , Java için, belgelerde özellikle belirtildiğini belirtir:

List.iterator()bu listedeki öğeler üzerinde uygun sırada bir yineleyici döndürür. "

C # belgelerinde buna benzer bir şey arıyorum.

Şimdiden teşekkürler.

Düzenleme: Tüm yanıtlarınız için hepinize teşekkür ederim (bu kadar hızlı yanıt almam şaşırtıcı). Tüm cevaplardan anladığım şey List<T>, her zaman indeksleme sırasına göre yineleniyor. Ancak yine de Java belgelerineList benzer şekilde bunu belirten açık bir belge görmek istiyorum .

Yanıtlar:


14

On Microsoft Referans Kaynağı sayfasında için List<T>Enumerator açıkça yineleme 0'dan Uzunluk-1 için yapılır belirtilmektedir:

internal Enumerator(List<T> list) {
    this.list = list;
    index = 0;
    version = list._version;
    current = default(T);
}

public bool MoveNext() {

    List<T> localList = list;

    if (version == localList._version && ((uint)index < (uint)localList._size)) 
    {                                                     
        current = localList._items[index];                    
        index++;
        return true;
    }
    return MoveNextRare();
}

Umarım birileri için hala önemlidir


102

Temel olarak kalmış IEnumeratoruygulanması - ama için List<T>her zaman doğal listesinin amacıyla, yani dizinleyicideki aynı sırayla gidecek: list[0], list[1], list[2]vb

Açıkça belgelendiğine inanmıyorum - en azından böyle bir dokümantasyon bulamadım - ama bence bunu garantili olarak değerlendirebilirsiniz. Bu sıralamadaki herhangi bir değişiklik, her türlü kodu anlamsız bir şekilde bozacaktır. Aslında, buna IList<T>uymayan herhangi bir uygulama görmek beni şaşırttı . Kuşkusuz özel olarak belgelendiğini görmek güzel olurdu ...


Kelimenin tam anlamıyla 5 saniye önce bir cevap için kontrol ettim ve benzer bir şey göndermek üzereydim. Çok hızlısın!
Michael G

Cevaplarınız için teşekkürler. Bunu garanti eden bazı belgeler var mı?
Matthijs Wessels

1
@Michael G: Belgeler olarak MSDN örnek koduna güvenmem. İçinde çok fazla korkunç hata gördüm.
Jon Skeet

1
Diziyle ilgili aynı cevabı veren var mı?
yazanpro

12
@yazanpro: foreachkesinlikle bir dizi ile sırayla yinelenecektir
Jon Skeet

8

Bağlantınızda, kabul edilen yanıt C # Dil Belirtimi Sürüm 3.0, sayfa 240'da belirtilmektedir :

Foreach'in bir dizinin elemanlarını geçtiği sıra şu şekildedir: Tek boyutlu diziler için elemanlar, endeks 0'dan başlayıp Uzunluk - 1 ile biten artan indeks sırasına göre gezilir. Çok boyutlu diziler için elemanlar arasında geçiş yapılır. öyle ki en sağdaki boyutun indisleri önce, sonra bir sonraki sol boyut ve böylece sola doğru artar. Aşağıdaki örnek, iki boyutlu bir dizideki her bir değeri öğe sırasına göre yazdırır:

using System;
class Test
{
  static void Main() {
      double[,] values = {
          {1.2, 2.3, 3.4, 4.5},
          {5.6, 6.7, 7.8, 8.9}
      };
      foreach (double elementValue in values)
          Console.Write("{0} ", elementValue);
      Console.WriteLine();
  }
}

Üretilen çıktı aşağıdaki gibidir: 1,2 2,3 3,4 4,5 5,6 6,7 7,8 8,9 Örnekte

int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
the type of n is inferred to be int, the element type of numbers.

2
Evet, ama bu bir dizi için. List <T> sınıfı için de otomatik olarak tutuyor mu?
Matthijs Wessels

2
List <T>, destek deposu için bir dizi kullanır. Yani evet.
Joel Mueller

9
Ama bu bir uygulama detayı. Bir diziyi destek deposu olarak kullanmak için List <T> gerekli değildir .
Eric Lippert

3
List <T> için belgelere işaret etmek istiyorum (örnek kodda): "List <(Of <(T>)>) sınıfı, ArrayList sınıfının genel eşdeğeridir. IList <(Of <(T>)>) boyutu gerektiği gibi dinamik olarak artırılan bir dizi kullanan genel arabirim . " (benim vurgu)
RCIX

Hmm, sanırım her zaman bir dizi kullanıyor. Ama yine de bu, tersine çevrilmiş bir numaralandırıcıyı döndüremeyeceği anlamına mı geliyor?
Matthijs Wessels

4

Sıra, bir foreach döngüsü kullanarak bir veri koleksiyonunda gezinmek için kullanılan yineleyici tarafından tanımlanır.

Dizine eklenebilen (Liste gibi) standart bir koleksiyon kullanıyorsanız, dizin 0'dan başlayıp yukarı doğru hareket eden koleksiyon boyunca ilerleyecektir.

Sıralamayı kontrol etmeniz gerekiyorsa , kendi IEnumerable'ınızı uygulayarak koleksiyonun yinelemesinin nasıl işleneceğini kontrol edebilir veya foreach döngüsünü çalıştırmadan önce listeyi istediğiniz şekilde sıralayabilirsiniz.

Bu, Numaralandırıcının genel Liste için nasıl çalıştığını açıklar . İlk başta, geçerli öğe tanımsızdır ve sonraki öğeye geçmek için MoveNext kullanır.

MoveNext'i okursanız , koleksiyonun ilk öğesiyle başlayacağını ve oradan koleksiyonun sonuna ulaşana kadar bir sonrakine geçeceğini belirtir.


Cevabınız ve eklediğiniz için teşekkürler (Herkes o kadar hızlı cevap veriyor ki, zar zor yetişebiliyorum). Ben de okudum. Belki sadece çok kesin olmak isteyen birini belirtmek için bir <kelime oluyorum>, ancak "ilk öğe" dediklerinde, yinelenecek olan ilk öğeyi kastettiklerini hissediyorum, buna göre ilk öğe değil yinelenen sınıfın sırasına göre.
Matthijs Wessels

Beklediğiniz gibi gittiğinden emin olmanız o kadar önemliyse, en iyi yol söylediklerimi yapmak ve IEnumerable'ı kendiniz uygulamaktır.
Brendan Enrick

1

Listeler, öğeleri destek deposunda bulundukları sırada iade ediyor gibi görünüyor - bu nedenle, listeye bu şekilde eklenirlerse, bu şekilde iade edilecekler.

Programınız sıralamaya bağlıysa, listeyi dolaşmadan önce onu sıralamak isteyebilirsiniz.

Doğrusal aramalar için biraz aptalca - ancak belirli bir şekilde siparişe ihtiyacınız varsa, en iyi bahsiniz, öğeleri bu sırayla yapmaktır.


1

Hızlı bir kod kırma işlemine benzer bir şey yapmak zorunda kaldım, ancak yapmaya çalıştığım şey için işe yaramadı, listeyi benim için yeniden sıraladı.

Sırayı değiştirmek için LINQ kullanma

         DataGridViewColumn[] gridColumns = new DataGridViewColumn[dataGridView1.Columns.Count];
         dataGridView1.Columns.CopyTo(gridColumns, 0); //This created a list of columns

         gridColumns = (from n in gridColumns
                        orderby n.DisplayIndex descending
                        select n).ToArray(); //This then changed the order based on the displayindex

Bunun soruyla nasıl bir ilgisi olduğunu anlamıyorum. Kodunuz bir List. Sanırım "liste" ile ne demek istediğimi yanlış anladınız.
Matthijs Wessels,

Ayrıca, neden içeriğini kopyalama Columnsiçin gridColumnsilk? Bence şunları da yapabilirsiniz:DataGridViewColumn[] gridColumns = dataGridView1.Columns.OrderByDescending(n => n.DisplayIndex).ToArray();
Matthijs Wessels

@MatthijsWessels İsterseniz Listeyi kullanmak için değiştirmek zor olmaz.
Austin Henley

@AustinHenley IOrderedEnumerable'da bir foreach yapabilirsiniz, ancak sorunun konusu bu değil. ToArray yerine ToList'e de yapabilirsiniz, ancak sonra tekrar bir Listeniz olur ve foreach'in daha sonra belirtilen sıradaki öğeler üzerinde döngü yapıp yapmayacağı sorusu hala cevapsızdır.
Matthijs Wessels
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.