Unterscheidung zwischen Iterator und Enumerator

77

Eine Interviewfrage für einen .NET 3.5-Job lautet "Was ist der Unterschied zwischen einem Iterator und einem Enumerator"?

Dies ist eine zentrale Unterscheidung, was mit LINQ usw. zu tun ist.

Was ist der Unterschied? Ich kann anscheinend keine solide Definition im Netz finden. Machen Sie keinen Fehler, ich kann die Bedeutung der beiden Begriffe finden, aber ich bekomme leicht unterschiedliche Antworten. Was wäre die beste Antwort für ein Interview?

IMO "iteriert" ein Iterator über eine Sammlung, und ein Enumerator bietet die Funktionalität zum Iterieren, dies muss jedoch aufgerufen werden.

Durch die Verwendung des Schlüsselwortsield wird auch der Status gespeichert. Was genau ist dieser Zustand? Gibt es ein Beispiel für diesen Vorteil?

GurdeepS
quelle

Antworten:

56

Iterieren bedeutet, einige Schritte zu wiederholen, während Aufzählen bedeutet, alle Werte in einer Sammlung von Werten durchzugehen. Das Aufzählen erfordert normalerweise eine Form der Iteration.

Auf diese Weise ist das Aufzählen ein Sonderfall des Iterierens, bei dem der Schritt einen Wert aus einer Sammlung erhält.

Beachten Sie, dass die "normalerweise" - Aufzählung auch rekursiv durchgeführt werden kann, aber Rekursion und Iteration so eng miteinander verbunden sind, dass mir dieser kleine Unterschied egal wäre.

Sie können auch Werte auflisten, die Sie nicht explizit in einer Sammlung speichern. Sie können beispielsweise die natürliche Zahl, die Primzahlen oder was auch immer aufzählen, aber Sie würden diese Werte während der Aufzählung berechnen und sie nicht aus einer physischen Sammlung abrufen. Sie verstehen diesen Fall als Aufzählung einer virtuellen Sammlung mit ihren durch eine Logik definierten Werten.


Ich nehme an, Reed Copsey hat es verstanden. In C # gibt es zwei Möglichkeiten, etwas aufzuzählen.

  1. Implementieren Enumerableund eine Klasse implementierenIEnumerator
  2. Implementieren Sie einen Iterator mit der yieldAnweisung

Der erste Weg ist schwieriger zu implementieren und verwendet Objekte zum Aufzählen. Der zweite Weg ist einfacher zu implementieren und verwendet Fortsetzungen.

Daniel Brückner
quelle
6
In C # ist ein Iterator jedoch ein spezifisches, spezielles Konstrukt sowie nur das Verb, das den Begriff beschreibt. Ein Enumerator ist ebenfalls eine bestimmte Schnittstelle. Die beiden haben in C # eine deutlich unterschiedliche Bedeutung als die normalen OO-Begriffe.
Reed Copsey
2
Oh ja, du hast recht. In meinen Begriffen ist dies alles eine Aufzählung und ich habe völlig vergessen, dass C # diesen Musteriterator aufruft.
Daniel Brückner
In C # ist der Iterator eine Methode, die einen Enumerator zurückgibt (Compilermagie, wenn er angezeigt wird yield), und der Enumerator ist ein Objekt, das nacheinander Werte mit Currentund liefert MoveNext()(siehe Pings Antwort ). Der Wortlaut unterscheidet sich in Python, wo ein Generator einem C # -Enumerator ähnelt (Werte, die im laufenden Betrieb mit erstellt werden yield), und der alte Iterator macht dasselbe, jedoch ohne yield(also kein Pausenmechanismus, eine Schleife kann nicht verwendet werden).
Minuten
46

In C # 2+ sind Iteratoren eine Möglichkeit für den Compiler, die IEnumerable- und / oder IEnumerable <T> -Schnittstellen automatisch für Sie zu generieren.

Ohne Iteratoren müssten Sie eine Klasse erstellen , die IEnumerator implementiert , einschließlich Current, MoveNext und Reset. Dies erfordert einen angemessenen Arbeitsaufwand. Normalerweise würden Sie eine private Klasse erstellen, die IEnumerator <T> für Ihren Typ implementiert, dann würde yourClass.GetEnumerator () diese private Klasse erstellen und zurückgeben.

Iteratoren sind eine Möglichkeit für den Compiler, dies mithilfe einer einfachen Syntax (Yield) automatisch für Sie zu generieren. Auf diese Weise können Sie GetEnumerator () direkt in Ihrer Klasse implementieren, ohne dass eine zweite Klasse (The IEnumerator) von Ihnen angegeben wird. Der Aufbau dieser Klasse mit all ihren Mitgliedern ist für Sie erledigt.

Iteratoren sind sehr entwicklerfreundlich - die Dinge werden auf sehr effiziente Weise und mit viel weniger Aufwand erledigt.

Wenn Sie foreach verwenden, verhalten sich die beiden identisch (vorausgesetzt, Sie schreiben Ihren benutzerdefinierten IEnumerator korrekt). Iteratoren machen das Leben einfach viel einfacher.

Reed Copsey
quelle
22

Was C # einen Iterator nennt, wird häufiger (außerhalb der C # -Welt) als Generator oder Generatorfunktion bezeichnet (z. B. in Python). Eine Generatorfunktion ist ein Spezialfall von Coroutine . AC # Iterator (Generator) ist eine spezielle Form eines Enumerators (ein Datentyp, der die IEnumerableSchnittstelle implementiert ).

Ich mag diese Verwendung des Begriffs Iterator für einen C # -Generator nicht, weil er genauso ein Enumerator wie ein Iterator ist. Für Microsoft ist es jedoch zu spät, um seine Meinung zu ändern.

Beachten Sie im Gegensatz dazu, dass in C ++ ein Iterator ein Wert ist, der hauptsächlich für den Zugriff auf sequentielle Elemente in einer Sammlung verwendet wird. Es kann erweitert, abgeleitet, um einen Wert abzurufen, und getestet werden, um festzustellen, ob das Ende der Sammlung erreicht wurde.

cdiggins
quelle
2
Nun, es ist die beste Antwort hier;)
mrzepa
13

"Während eine foreach-Anweisung der Verbraucher des Enumerators ist, ist ein Iterator der Produzent des Enumerators."

Das Obige erklärt es wie "C # 5.0 In A NutShell" und war für mich hilfreich.

Mit anderen Worten, die foreach-Anweisung verwendet MoveNext () und die Current-Eigenschaft des IEnumerator, um eine Sequenz zu durchlaufen, während der Iterator verwendet wird, um die Implementierung des IEnumerator zu erstellen, die von der foreach-Anweisung verwendet wird. Wenn Sie in C # eine Iteratormethode schreiben, die eine Yield-Anweisung enthält, generiert der Compiler einen privaten Enumerator für Sie. Wenn Sie die Elemente in der Sequenz durchlaufen, werden die Eigenschaften MoveNext () und Current des privaten Enumerators aufgerufen. Diese Methoden / Eigenschaften werden von Ihrem Code in der Iterator-Methode implementiert, die wiederholt aufgerufen wird, um Werte zu erhalten, bis keine Werte mehr zu ergeben sind.

Dies ist mein Verständnis davon, wie C # Enumeratoren und Iteratoren definiert.

Klingeln
quelle
1
Dieser Satz fasst es sehr kurz zusammen. Schade, dass diese Antwort so weit unten ist, habe meine +1!
AnorZaken
12

Um Iteratoren zu verstehen, müssen wir zuerst Enumeratoren verstehen.

Enumeratoren sind Spezialobjekte, die es einem ermöglichen, sich einzeln durch eine geordnete Liste von Elementen zu bewegen (das Gleiche wird manchmal als "Cursor" bezeichnet). Das .NET Framework bietet zwei wichtige Schnittstellen für Enumeratoren: IEnumerator und IEnumerable. Objekte, die IEnumerator implementieren, sind selbst Enumeratoren. Sie unterstützen die folgenden Mitglieder:

  • die Eigenschaft Current, die auf eine Position in der Liste verweist

  • die Methode MoveNext, mit der das aktuelle Element um eins in der Liste verschoben wird

  • die Methode Zurücksetzen, mit der das aktuelle Element an seine Ausgangsposition (vor dem ersten Element) verschoben wird.

Auf der anderen Seite implementieren Iteratoren das Aufzählungsmuster. In .NET 2.0 wurde der Iterator eingeführt, der ein vom Compiler manipulierter Enumerator ist. Wenn das Aufzählungsobjekt GetEnumerAtor entweder direkt oder indirekt aufruft, generiert der Compiler ein geeignetes Iteratorobjekt und gibt es zurück. Optional kann der Iterator ein kombiniertes Aufzählungs- und Aufzählungsobjekt sein.

Der wesentliche Bestandteil eines Iteratorblocks ist die Ertragsangabe. Es gibt einen großen Unterschied zwischen Iteratoren und Enumeratoren: Iterateure implementieren die Reset-Methode nicht. Das Ausführen der Reset-Methode auf einem Iterator kann eine Ausnahme darstellen.

Der Zweck von Iteratoren besteht darin, die einfache Implementierung von Enumeratoren zu ermöglichen. Wenn eine Methode entweder einen Enumerator oder eine Enumerable-Klasse für eine geordnete Liste von Elementen zurückgeben muss, wird sie so geschrieben, dass jedes Element in der richtigen Reihenfolge mit der Anweisung'ield 'zurückgegeben wird.

Joshua
quelle
8

Da keine Beispiele angegeben wurden, ist hier eines, das mir hilfreich war.

Ein Enumerator ist ein Objekt, das Sie erhalten, wenn Sie .GetEnumerator () für eine Klasse oder einen Typ aufrufen, der die IEnumerator-Schnittstelle implementiert. Wenn diese Schnittstelle implementiert ist, haben Sie den gesamten Code erstellt, der für den Compiler erforderlich ist, damit Sie foreachIhre Sammlung "iterieren" können.

Verwechseln Sie das Wort "iterieren" nicht mit dem Iterator. Sowohl mit dem Enumerator als auch mit dem Iterator können Sie "iterieren". Aufzählung und Iteration sind im Grunde der gleiche Prozess, werden jedoch unterschiedlich implementiert. Aufzählung bedeutet, dass Sie die IEnumerator-Schnittstelle implementiert haben Iterieren bedeutet, dass Sie das Iterator-Konstrukt in Ihrer Klasse erstellt haben (siehe unten) und foreachIhre Klasse aufrufen. Zu diesem Zeitpunkt erstellt der Compiler automatisch die Enumerator-Funktionalität für Sie.

Beachten Sie auch, dass Sie nicht mit Ihrem Enumerator in die Hocke gehen müssen. Sie können den MyClass.GetEnumerator()ganzen Tag anrufen und nichts damit anfangen (Beispiel:

IEnumerator myEnumeratorThatIWillDoNothingWith = MyClass.GetEnumerator()).

Beachten Sie auch, dass Ihr Iterator-Konstrukt in Ihrer Klasse nur dann wirklich verwendet wird, wenn Sie es tatsächlich verwenden, dh Sie haben foreachIhre Klasse aufgerufen .

Hier ist ein Iterator-Beispiel von msdn :

public class DaysOfTheWeek : System.Collections.IEnumerable
{

     string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

     //This is the iterator!!!
     public System.Collections.IEnumerator GetEnumerator()
     {
         for (int i = 0; i < days.Length; i++)
         {
             yield return days[i];
         }
     }

}

class TestDaysOfTheWeek
{
    static void Main()
    {
        // Create an instance of the collection class
        DaysOfTheWeek week = new DaysOfTheWeek();

        // Iterate with foreach - this is using the iterator!!! When the compiler
        //detects your iterator, it will automatically generate the Current, 
        //MoveNext and Dispose methods of the IEnumerator or IEnumerator<T> interface
        foreach (string day in week)
        {
            System.Console.Write(day + " ");
        }
    }
}
// Output: Sun Mon Tue Wed Thr Fri Sat
Richard
quelle
4

"Iteratoren sind eine neue Funktion in C # 2.0. Ein Iterator ist eine Methode, ein Accessor oder ein Operator, mit der Sie jede Iteration in einer Klasse oder Struktur unterstützen können, ohne die gesamte IEnumerable-Schnittstelle implementieren zu müssen. Stattdessen stellen Sie nur einen Iterator bereit Durchläuft einfach die Datenstrukturen in Ihrer Klasse. Wenn der Compiler Ihren Iterator erkennt, generiert er automatisch die Methoden Current, MoveNext und Dispose der IEnumerable- oder IEnumerable-Schnittstelle. " - msdn

John Ellinwood
quelle
2

Die Aufzählung behandelt Objekte, während die Iteration nur Werte behandelt. Die Aufzählung wird verwendet, wenn wir die Vektor-Hashtabelle usw. verwenden, während die Iteration in der while-Schleife für die Schleife usw. verwendet wird. Ich habe das Schlüsselwort yield nie verwendet, daher konnte ich es Ihnen nicht sagen.

Kredns
quelle
Das mag wahr sein, aber nur für Punktnetz. In einigen Sprachen können Sie Objekte / Werte iterieren und Objekte / Werte aufzählen
Tim Matthews
Nun, ich bin ein .NET-Programmierer. Entschuldigung für meine Unwissenheit, so habe ich gelernt, wie sie funktionieren.
Kredns
0

Die Iteration befasst sich mit Arrays und Strings, während sich die Iteration mit Objekten befasst

In JavaScript können Sie ein Array oder eine Zeichenfolge iterieren mit:

  • für jede Schleife
  • für Schleife
  • für von Loop
  • tun, während Schleife
  • während Schleife

Und Sie können ein Objekt aufzählen mit:

  • für in Schleife
  • Object.keys () Methode
  • Object.values () Methode
  • Object.entries () Methode
Naimur Rahman Khan
quelle