2010-12-02 19 views
33

Arbeits von foreach: ich weiß,Zähler in foreach Schleife in C#

foreach ist eine Schleife, die iteriert durch eine Sammlung oder ein Array einer nach eins, bis die von 0 Index begonnen letzter Gegenstand der Sammlung.

Also, wenn ich n Elemente in einem Array habe.

foreach (var item in arr) 
{ 

} 

dann, In, 1. Iteration item = arr [0];
dann in der 2., item = arr [1];
.
.
.
in den letzten (n-ten), item = arr [n-1];

Fazit: davon arbeiten scheint bei jeder Iteration, dass sie das weiß, welcher Wert von Array genommen werden oder es kennt den Index des Elements aus dem Feld genommen werden.

Jetzt meine Frage: Wie kann ich Index eines Artikels erhalten, ohne eine neue Variable zu verwenden?

foreach (string item in mylist) 
{ 
    if (item == "myitem") 
    { 
     // get index of item 
     break; 
    } 
} 
+0

Die kanonische Frage ist * [Wie Sie den Index der aktuellen Iteration einer foreach-Schleife erhalten Sie?] (Http://stackoverflow.com/questions/43021) *. –

+1

Mögliches Duplikat von * [Wie erhalten Sie den Index der aktuellen Iteration einer foreach-Schleife?] (Http://stackoverflow.com/questions/43021/how-do-you-get-the-index-of-the - aktuelle Iteration einer foreach-Schleife) *. –

Antwort

69

Es hängt davon ab, was Sie mit "es" meinen. Der Iterator weiß, welchen Index er erreicht hat, ja - im Fall eines List<T> oder eines Arrays. Aber es gibt keinen allgemeinen Index innerhalb IEnumerator<T>. Ob es um eine indizierte Sammlung geht oder nicht, hängt von der Implementierung ab. Viele Sammlungen unterstützen keine direkte Indizierung.

(In der Tat, foreach nicht immer einen Iterator überhaupt. Wenn der Kompilierung-Typ der Sammlung ein Array ist, wird der Compiler iterieren es array[0] verwenden, array[1] usw. Ebenso ist die Sammlung kann eine haben Verfahren genannt GetEnumerator() die eine Art mit den entsprechenden Mitgliedern zurückgibt, aber ohne Durchführung der IEnumerable/IEnumerator in sight)

Optionen für die Aufrechterhaltung eines Index.

  • Verwenden einer for Schleife
  • Verwenden Sie eine separate Variable
  • Verwenden Sie eine Projektion, die jedes Element zu einem Index/Wert-Paar projiziert, z.

    foreach (var x in list.Select((value, index) => new { value, index })) 
    { 
        // Use x.value and x.index in here 
    } 
    
  • meine SmartEnumerable Klasse verwenden, die ein wenig wie die vorherige Option ist

Alle aber die erste dieser Optionen funktionieren wird, ob die Sammlung natürlich indiziert ist.

+0

@Downvoter: Interessieren Sie sich für einen Kommentar? –

+0

Jon ...... Ich bin ein großer Fan von deinen Antworten. – AlwaysAProgrammer

+1

Ihre Projektion Ansatz ist elegant und einfach, ich werde das kneifen! – madman1969

17

Verwenden for statt foreach. foreach nicht ihr Innenleben aussetzen, aufzählt es alles, was IEnumerable ist (die keinen Index überhaupt haben muss).

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

Außerdem, wenn was Sie versuchen, den Index eines bestimmten Elements in der Liste zu tun ist, zu finden, Sie haben es gar nicht selbst zu wiederholen. Verwenden Sie stattdessen Array.IndexOf(item).

+0

Ich denke, das sollte ich sein JasonS

+0

Whoops. Das stimmt natürlich. Vielen Dank. –

+0

Wie schon mehrfach in anderen Antworten erwähnt, muss es IEnumerable sein, um in einer Foreach zu arbeiten. –

1

Dies gilt nur, wenn Sie durch ein Array iterieren; Was wäre, wenn Sie durch eine andere Art von Sammlung iterieren würden, die keine Ahnung vom Indexzugriff hat? In der array-Methode besteht der einfachste Weg, den Index beizubehalten, darin, einfach eine for-Schleife zu verwenden.

10

Ihr Verständnis von foreach ist unvollständig.

Es funktioniert mit jedem Typ, der IEnumerable verfügbar macht (oder implementiert eine GetEnumerable-Methode) und verwendet die zurückgegebene IEnumerator, um über die Elemente in der Auflistung zu durchlaufen.

Wie die Enumerator dies tut (mit einem Index, yield Anweisung oder Magie) ist ein Implementierungsdetail.

Um dies zu erreichen, was Sie wollen, sollten Sie eine for Schleife verwenden:

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

Hinweis:

die Anzahl der Elemente in einer Liste zu erhalten ist etwas anders, je nach Art der Liste

For Collections: Use Count [property] 
For Arrays:  Use Length [property] 
For IEnumerable: Use Count() [Linq method] 
+0

Ich denke, es ist Magie. – Brad

+0

'foreach' funktioniert eigentlich mit jedem Typ, der eine 'GetEnumerator'-Methode hat (wenn diese Methode dann ein Objekt mit einer passenden' Current'-Eigenschaft und' MoveNext'-Methode zurückgibt). Die Typen müssen "IEnumerable"/"IEnumerator" nicht implementieren. – LukeH

+0

@LukeH - Messepunkt. Antwort aktualisiert – Oded

0

Nicht alle Sammlungen haben Indizes. Zum Beispiel kann ich einen Dictionary mit foreach verwenden (und durchlaufen alle Schlüssel und Werte), aber ich kann an einzelnen Elemente nicht schreiben bekommen dictionary[0] verwenden, dictionary[1] usw.

Wenn ich wollte durch ein Wörterbuch iterieren und um einen Index zu verfolgen, müsste ich eine separate Variable verwenden, die ich selbst inkrementiert habe.

2

Wahrscheinlich sinnlos, aber ...

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

Die Sequenz in einer foreach-Schleife wiederholt werden möglicherweise nicht Indizierung unterstützen oder zu wissen, ein solches Konzept braucht es nur eine Methode zur Implementierung namens GetEnumerator, die ein Objekt zurückgibt, dass als Ein Minimum hat die Schnittstelle von IEnumerator, obwohl es nicht erforderlich ist. Wenn Sie wissen, dass das, was Sie iterieren, Indexierung unterstützt und Sie den Index benötigen, schlage ich vor, stattdessen eine for-Schleife zu verwenden.

Ein Beispiel Klasse, die in foreach verwendet werden kann:

class Foo { 

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

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

      public bool MoveNext() { 
       incantation 
      } 
     } 
    } 
+0

'GetEnumerator()' muss nicht einmal einen Typ zurückgeben, der 'IEnumerator' implementiert ... –

+0

@ Jon Skeet: Was meinst du? Ist IEnumerator GetEnumerator() nicht die Signatur der einzigen Methode, die in IEnumerable definiert ist? –

+0

@Yodan: Ja, aber du musst IEnumerable auch nicht implementieren :) –

0

von MSDN:

Die foreach Anweisung wiederholt eine Gruppe der eingebetteten Anweisungen für jedes Element in einem Array oder ein Objekt Sammlung, die die System.Collections.IEnumerable oder System.Collections.Generic.IEnumerable implementiert (Of T) Schnittstelle.

Also, es ist nicht unbedingt Array. Es könnte sogar eine faule Sammlung sein, die keine Ahnung von der Anzahl der Gegenstände in der Sammlung hat.

5

Oder noch einfacher, wenn Sie nicht viel linq verwenden möchten und aus irgendeinem Grund keine for-Schleife verwenden möchten.

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

Yeah das Leben ist einfach. –

+0

Sie haben 'arr.Length' Als Sammlung, soll es 'foreach (var x in arr)' sein? – karthick

+0

@karthick - Wow, es war fast 4 Jahre her, dass ich das geschrieben habe, aber du bist natürlich richtig, komisch, dass niemand sonst das vor dir entdeckt hat :) Lass mich bearbeiten, wenn ich es noch kann. – BlueVoodoo