各ループのC#はList <T>をどのような順序で繰り返しますか?


84

C#のforeachループがSystem.Collections.Generic.List<T>オブジェクトをループする順序について疑問に思っていました。

同じトピックについて別の質問を見つけましたが、それが私の質問に満足のいく答えになるとは感じていません。

誰かが順序が定義されていないと述べています。しかし、他の誰かが述べているように、配列をトラバースする順序は固定されています(0から長さ-1まで)。8.8.4foreachステートメント

順序のある標準クラスにも同じことが当てはまるとも言われています(例List<T>)。それをバックアップするためのドキュメントが見つかりません。ですから、今はそのように機能するかもしれませんが、次の.NETバージョンでは異なる可能性があります(可能性は低いかもしれませんが)。

私もList(t).Enumerator運が悪かったのでドキュメントを見ました。

別の関連する質問は、Javaの場合、ドキュメントに具体的に記載されていると述べています。

List.iterator()このリストの要素に対して適切な順序でイテレータを返します。」

私はC#のドキュメントでそのようなものを探しています。

前もって感謝します。

編集:すべての回答をありがとうございました(私が非常に多くの返信を受け取ったのは驚くべきことです)。すべての回答から私が理解しているのは、List<T>常にインデックスの順序で繰り返されるということです。しかし、のJavaドキュメントListと同様に、これを示すドキュメントの明確な平和を望んでいます。

回答:


14

のMicrosoftリファレンスソース]ページのためのList<T>列挙子明示的に反復が0から長さ-1に行われていることが述べられています。

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

それがまだ誰かに関連していることを願っています


102

基本的には最大だIEnumerator実装-しかし、のためにList<T>、それは常に自然リストの順番、すなわちインデクサと同じ順序で行く:list[0]list[1]list[2]など

明示的に文書化されているとは思いませんが、少なくともそのような文書は見つかりませんでしたが、保証されたものとして扱うことができると思います。その順序を変更すると、あらゆる種類のコードが無意味に破損します。実際、IList<T>これに従わなかった実装を見て驚いたでしょう。確かに、それが具体的に文書化されているのを見るのは素晴らしいことです...


私は文字通り5秒前に答えをチェックし、似たようなものを投稿しようとしていました。あなたは速すぎます!
Michael G

返信ありがとうございます。これを保証するドキュメントはありますか?
Matthijs Wessels

1
@Michael G:ドキュメントとしてMSDNサンプルコードに依存することはありません。恐ろしいエラーが多すぎます。
Jon Skeet

1
誰かがアレイに関して同じ答えを提供できますか?
yazanpro 2013年

12
@yazanpro:foreach配列で順番に確実に反復します。
Jon Skeet 2013年

8

リンクで、受け入れられた回答はC#言語仕様バージョン3.0、240ページに記載されています

foreachが配列の要素をトラバースする順序は、次のとおりです。1次元配列の場合、要素は、インデックス0から始まり、インデックスの長さ– 1で終わる、インデックスの昇順でトラバースされます。多次元配列の場合、要素はトラバースされます。右端の次元のインデックスが最初に増加し、次に左の次元が増加し、以下同様に左側に増加します。次の例では、2次元配列の各値を要素順に出力します。

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

生成される出力は次のとおりです。1.22.33.44.5 5.6 6.7 7.88.9例では

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
はい。ただし、これはアレイ用です。List <T>クラスにも自動的に適用されますか?
Matthijs Wessels

2
List <T>は、バッキングストアに配列を使用します。あ、はい。
Joel Mueller

9
しかし、それは実装の詳細です。List <T>は、配列をバッキングストアとして使用する必要はありません。
Eric Lippert

3
List <T>のドキュメントを(サンプルコードに)指摘したいと思います。「List <(Of <(T>)>)クラスはArrayListクラスの一般的な同等物です。IList<(Of <(T>)>)必要に応じてサイズが動的に増加する配列を使用する汎用インターフェース。 " (強調鉱山)
RCIX 2009年

うーん、その時はいつも配列を使っていると思います。しかし、それでも、逆の列挙子を返すことができないということですか?
Matthijs Wessels

4

順序は、foreachループを使用してデータのコレクションをトラバースするために使用されるイテレーターによって定義されます。

インデックス付け可能な標準コレクション(リストなど)を使用している場合は、インデックス0から始まり、上に向かってコレクションをトラバースします。

順序を制御する必要がある場合は、独自のIEnumerableを実装してコレクションの反復を処理する方法を制御するか、foreachループを実行する前にリストを希望どおりに並べ替えることができます。

これは、列挙子がジェネリックリストに対してどのように機能するかを説明しています。最初、現在の要素は未定義であり、MoveNextを使用して次のアイテムに移動します。

MoveNextを読むと、コレクションの最初の要素から始まり、そこからコレクションの最後に到達するまで次の要素に移動することが示されます。


返信と追加をありがとう(誰もがとても速く答えているので、私はほとんどついていけません)。私もそれを読みました。<正確になりたい人を特定する言葉>なのかもしれませんが、「最初の要素」とは、最初に繰り返される要素ではなく、繰り返される最初の要素を意味しているように感じます。反復クラスの順序に。
Matthijs Wessels

それが期待どおりに進むことを確信することが非常に重要である場合、最善の方法は、私が言ったことを実行し、IEnumerableを自分で実装することです。
ブレンダンエンリック2009年

1

リストは、バッキングストアにある順序でアイテムを返すように見えます。したがって、その方法でリストに追加された場合は、その方法で返されます。

プログラムが順序に依存している場合は、リストをトラバースする前にプログラムを並べ替えることができます。

線形検索ではややばかげていますが、特定の方法で順序が必要な場合は、その順序でアイテムを作成するのが最善の策です。


1

コードの簡単なハックと同じようなことをしなければなりませんでしたが、それは私がやろうとしていたことにはうまくいきませんでしたが、リストを並べ替えてくれました。

LINQを使用して順序を変更する

         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

これが質問とどのように関連しているかわかりません。あなたのコードはList。を使用していません。私が「リスト」とはどういう意味か誤解されたと思います。
Matthijs Wessels 2012

また、なぜあなたはの内容コピーしているColumnsgridColumns最初の?あなたもできると思います:DataGridViewColumn[] gridColumns = dataGridView1.Columns.OrderByDescending(n => n.DisplayIndex).ToArray();
Matthijs Wessels 2012

@MatthijsWessels必要に応じて、Listを使用するように変更するのは難しくありません。
オースティンヘンリー2012

@AustinHenley IOrderedEnumerableでforeachを実行できますが、それは問題の内容ではありません。ToArrayの代わりにToListを実行することもできますが、リストが再び表示され、foreachが指定された順序でアイテムをループするかどうかという質問にはまだ回答がありません。
Matthijs Wessels 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.