web-dev-qa-db-ja.com

C#のforeachループのカウンター

foreachの動作:私が知っているように、

foreachは、インデックス0からコレクションの最後のアイテムまで、コレクションまたは配列を1つずつ繰り返すループです

したがって、配列にn個のアイテムがある場合。

foreach (var item in arr)
{

}  

次に、In、1回目の反復、item = arr [0];
次に、2番目に、item = arr [1];



in last(nth)、item = arr [n-1];

結論:動作から、各反復で、配列から取得する値または配列から取得するアイテムのインデックスを知っているようです。

今私の質問:新しい変数を使用せずにアイテムのインデックスを取得するにはどうすればよいですか?

foreach (string item in mylist)
{
   if (item == "myitem")
   {
       // get index of item
       break;
   }
}
41
Javed Akram

「it」の意味に依存します。イテレータは、到達したインデックスを知っています、はい-List<T>または配列の場合。しかし、IEnumerator<T>内には一般的なインデックスはありません。インデックス付きコレクションを反復処理するかどうかは、実装次第です。多数のコレクションは、直接インデックス作成をサポートしていません。

(実際、foreachは常にイテレーターを使用しません。コレクションのコンパイル時の型が配列の場合、コンパイラーはarray[0]array[1]などを使用して反復処理を行います。同様に、コレクションはGetEnumerator()と呼ばれるメソッドで、適切なメンバーを持つ型を返しますが、IEnumerable/IEnumeratorの実装はありません。)

インデックスを維持するためのオプション:

  • forループを使用する
  • 別の変数を使用する
  • 各アイテムをインデックス/値のペアに投影するプロジェクションを使用します。

     foreach (var x in list.Select((value, index) => new { value, index }))
     {
         // Use x.value and x.index in here
     }
    
  • SmartEnumerable クラスを使用します。これは前のオプションに少し似ています

これらのオプションの最初を除くすべては、コレクションが自然にインデックス付けされているかどうかにかかわらず機能します。

81
Jon Skeet

forの代わりにforeachを使用します。 foreachはその内部の動作を公開せず、IEnumerable(インデックスをまったく必要としない)であるものをすべて列挙します。

_for (int i=0; i<arr.Length; i++)
{
    ...
}
_

また、リスト内の特定のアイテムのインデックスを見つけようとしている場合は、自分でそれを繰り返す必要はありません。代わりにArray.IndexOf(item)を使用してください。

18
Yodan Tauber

foreachの理解が不完全です。

IEnumerableを公開する(またはGetEnumerableメソッドを実装する)任意のタイプで動作し、返されたIEnumeratorを使用してコレクション内のアイテムを反復処理します。

Enumeratorがこれを行う方法(インデックス、yieldステートメントまたはマジックを使用)は、実装の詳細です。

目的を達成するには、forループを使用する必要があります。

for (int i = 0; i < mylist.Count; i++)
{
}

注意:

リスト内のアイテム数の取得は、リストのタイプによってわずかに異なります

For Collections: Use Count   [property]
For Arrays:      Use Length  [property]
For IEnumerable: Use Count() [Linq method]
11
Oded

または、多くのlinqを使用したくなく、何らかの理由でforループを使用したくない場合は、さらに簡単です。

int i = 0;
foreach(var x in arr)
{
   //Do some stuff
   i++;
}
7
BlueVoodoo

おそらく無意味ですが、...

foreach (var item in yourList.Select((Value, Index) => new { Value, Index }))
{
    Console.WriteLine("Value=" + item.Value + ", Index=" + item.Index);
}
2
LukeH

これは、配列を反復処理する場合にのみ当てはまります。インデックスによるアクセスの概念を持たない別の種類のコレクションを繰り返し処理している場合はどうでしょうか?配列の場合、インデックスを保持する最も簡単な方法は、単にVanilla forループを使用することです。

1
Dan Bryant

カスタムForeachバージョンなし:

_datas.Where((data, index) =>
{
    //Your Logic
    return false;
}).Any();
_

いくつかの単純なケースでは、私の方法は_where + false + any_を使用しています。
それはforeach + select((data,index)=>new{data,index})より少し致命的で、カスタムのForeachメソッドはありません。

MyLogic:

  • statement bodyを使用してロジックを実行します。
  • falseを返すであるため、新しいEnumrableデータカウントはゼロです。
  • Any() yeildを実行させます。

ベンチマークテストコード

_[RPlotExporter, RankColumn]
public class BenchmarkTest
{
    public static IEnumerable<dynamic> TestDatas = Enumerable.Range(1, 10).Select((data, index) => $"item_no_{index}");

    [Benchmark]
    public static void ToArrayAndFor()
    {
        var datats = TestDatas.ToArray();
        for (int index = 0; index < datats.Length; index++)
        {
            var result = $"{datats[index]}{index}";
        }
    }

    [Benchmark]
    public static void IEnumrableAndForach()
    {
        var index = 0;
        foreach (var item in TestDatas)
        {
            index++;
            var result = $"{item}{index}";
        }
    }

    [Benchmark]
    public static void LinqSelectForach()
    {
        foreach (var item in TestDatas.Select((data, index) => new { index, data }))
        {
            var result = $"{item.data}{item.index}";
        }
    }

    [Benchmark]
    public static void LinqSelectStatementBodyToList()
    {
        TestDatas.Select((data, index) =>
        {
            var result = $"{data}{index}";
            return true;
        }).ToList();
    }

    [Benchmark]
    public static void LinqSelectStatementBodyToArray()
    {
        TestDatas.Select((data, index) =>
        {
            var result = $"{data}{index}";
            return true;
        }).ToArray();
    }

    [Benchmark]
    public static void LinqWhereStatementBodyAny()
    {
        TestDatas.Where((data, index) =>
        {
            var result = $"{data}{index}";
            return false;
        }).Any();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<BenchmarkTest>();

        System.Console.Read();
    }
}
_

ベンチマーク結果:

_                         Method |     Mean |     Error |    StdDev | Rank |
------------------------------- |---------:|----------:|----------:|-----:|
                  ToArrayAndFor | 4.027 us | 0.0797 us | 0.1241 us |    4 |
            IEnumrableAndForach | 3.494 us | 0.0321 us | 0.0285 us |    1 |
               LinqSelectForach | 3.842 us | 0.0503 us | 0.0471 us |    3 |
  LinqSelectStatementBodyToList | 3.822 us | 0.0416 us | 0.0389 us |    3 |
 LinqSelectStatementBodyToArray | 3.857 us | 0.0764 us | 0.0785 us |    3 |
      LinqWhereStatementBodyAny | 3.643 us | 0.0693 us | 0.0712 us |    2 |
_
1
IT WeiHan

すべてのコレクションにインデックスがあるわけではありません。たとえば、Dictionaryforeachとともに使用できます(そしてすべてのキーと値を反復処理できます)が、_dictionary[0]_、_dictionary[1]_など.

辞書を反復処理してインデックスを追跡したい場合は、自分でインクリメントした別の変数を使用する必要があります。

0
Tim Robinson

Foreachループで繰り返されるシーケンスは、インデックス付けをサポートしていないか、実装を必要としないが、少なくともIEnumeratorのインターフェイスを持つオブジェクトを返すGetEnumeratorと呼ばれるメソッドを実装する必要があるような概念を知っていない場合があります。繰り返し処理がインデックス作成をサポートし、インデックスが必要なことがわかっている場合は、代わりにforループを使用することをお勧めします。

foreachで使用できるサンプルクラス:

    class Foo {

        public iterator GetEnumerator() {
            return new iterator();
        }

        public class iterator {
            public Bar Current {
                get{magic}
            }

            public bool MoveNext() {
                incantation
            }
        }
    }
0
Rune FS

MSDNから:

Foreachステートメントは、System.Collections.IEnumerableまたはSystem.Collections.Generic.IEnumerable(Of T)インターフェイスを実装する配列またはオブジェクトコレクションの各要素に対して、埋め込みステートメントのグループを繰り返します。

したがって、必ずしも配列ではありません。コレクション内のアイテムの数がわからない、怠collectionなコレクションでさえあり得ます。

0