2009-08-20 5 views
6

Pseudo-Code:Warum schränken einige Programmiersprachen Sie davon ab, das Array zu bearbeiten, das Sie durchlaufen?

for each x in someArray { 
    // possibly add an element to someArray 
} 

ich den Namen der Ausnahme vergessen dies in einigen Sprachen wirft.

Ich bin neugierig zu wissen warum einige Sprachen verbieten diesen Anwendungsfall, während andere Sprachen es erlauben. Sind die erlaubten Sprachen unsicher - offen für einige Fallstricke? Oder sind die verbietenden Sprachen einfach übervorsichtig oder vielleicht faul (sie hätten die Sprache implementieren können, um diesen Fall elegant zu behandeln, aber haben sich einfach nicht darum gekümmert).

Danke!

+1

warum die down votes? Dies ist eine legitime Programmiersprache Design-Frage. –

+0

Ich kann mir keine Sprache (die ich benutzt habe) vorstellen, die es nicht erlaubt, _attempt_ zu bearbeiten. Sie könnten in Nebenläufigkeit Probleme auftreten, wenn Sie unter anderem das 'x' aus dem' someArray' entfernen. –

+0

Dies erfordert den Namen der Sprachen und die Ausnahmen, die ausgelöst werden, und sogar den Code, der das Problem verursacht hat. Einfach ausgedrückt, vielleicht haben Sie nicht getan, was Sie dachten, Sie würden tun. Wenn nicht ergänzt, werde ich dafür stimmen, es zu schließen. –

Antwort

9

Wie möchten Sie das Verhalten haben?

list = [1,2,3,4] 
foreach x in list: 
    print x 
    if x == 2: list.remove(1) 

mögliche Verhaltensweisen:

Liste ist einig verketteten Liste Typ Iterator, wo Deletionen nicht Ihren aktuellen Iterator beeinflussen:

[1,2,3,4] 

Liste ist einige Array, wo Sie Ihren Iterator iteriert über Zeigerinkrement:

[1,2,4] 

Wie zuvor, nur das System versucht zu cac er die Iteration zählen

[1,2,4,<segfault>] 

Das Problem ist, dass verschiedene Sammlungen dieses enumerable/Sequenz-Schnittstelle implementiert, die für die foreach-Looping haben unterschiedliche Verhaltensweisen ermöglicht.

3

Angenommen, Ihr Array hat 10 Elemente. Sie gelangen zum 7. Element und entscheiden dort, dass Sie ein neues Element früher im Array hinzufügen müssen. Oh, oh! Dieses Element wird nicht wiederholt! for each hat die Semantik, zumindest für mich, auf jeder einzelnen Element des Arrays, einmal und nur einmal zu arbeiten.

1

Ihr Pseudo-Beispielcode würde zu einer Endlosschleife führen. Für jedes Element, das Sie betrachten, fügen Sie eins zur Sammlung hinzu. Wenn Sie also mindestens ein Element haben, haben Sie i (iterativer Zähler) + 1 Elemente.

+1

Er sagt "möglicherweise hinzufügen" nicht "immer hinzufügen" :) – nos

1

Arrays sind normalerweise in der Anzahl der Elemente festgelegt. Durch umschlossene Objekte (z. B. List) erhalten Sie flexible Breiten, die Flexibilität ermöglichen. Ich vermute, dass die Sprache Probleme haben könnte, wenn der von ihnen verwendete Mechanismus ein ganz neues Array erstellen würde, um die Bearbeitung zu ermöglichen.

4

Je nach Sprache (oder Plattform, als .Net) kann die Iteration anders implementiert werden.

In der Regel erstellt ein Foreach ein Iterator- oder Enumerator-Objekt auf dem Array, das intern seinen Status über die Iterationsdetails behält. Wenn Sie das Array ändern (indem Sie ein Element hinzufügen oder löschen), wäre der Iteratorstatus in Bezug auf den neuen Status des Arrays inkonsistent.

Mit Plattformen wie .Net können Sie eigene Enumeratoren definieren, die möglicherweise keine Elemente des zugrunde liegenden Arrays hinzufügen/entfernen können.

Eine generische Lösung für das Problem des Hinzufügens/Entfernens von Elementen beim Iterieren besteht darin, die Elemente in einer neuen Liste/Sammlung/Array zu sammeln und die gesammelten Elemente nach Abschluss der Aufzählung hinzuzufügen/zu entfernen.

0

Um die Listen und Enumeratoren zu implementieren, würde dies eine Menge Overhead bedeuten. Dieser Overhead wäre immer da und würde nur in einer großen Minderheit der Fälle nützlich sein.

Auch jede gewählte Implementierung wäre nicht immer sinnvoll. Nehmen wir zum Beispiel den einfachen Fall des Einfügens eines Elements in die Liste während der Aufzählung, würde das neue Element immer in der Aufzählung enthalten sein, immer ausgeschlossen, oder sollte das davon abhängen, wo in der Liste das Element hinzugefügt wurde? Wenn ich das Element an der aktuellen Position einfügen würde, würde das den Wert der Current-Eigenschaft des Enumerators ändern, und sollte es das aktuell aktuelle Element überspringen, das dann das nächste Element ist?

0

Dies geschieht nur innerhalb von foreach-Blöcken. Verwenden Sie eine for-Schleife mit einem Indexwert, die Ihnen erlaubt ist. Stellen Sie sicher, dass Sie rückwärts durchlaufen, damit Sie Elemente löschen können, ohne Probleme zu verursachen.

0

Von der Spitze meines Kopfes könnte es zwei Szenarien der Implementierung von Iteration auf einer Sammlung geben.

  1. die Iterator iteriert über die Sammlung, für die es geschaffen wurde

  2. die Iterator iteriert über eine Kopie der Sammlung, für die sie

erstellt wurde, wenn Änderungen an der gemacht werden Die erste Option sollte entweder ihre Iterationssequenz aktualisieren (was sehr schwer oder sogar unmöglich zuverlässig sein kann) oder einfach die Möglichkeit ablehnen (eine Ausnahme auslösen). Der letzte ist offensichtlich die sichere Option.

In der zweiten Option können Änderungen an der ursprünglichen Sammlung vorgenommen werden, ohne die Iterationssequenz zu stören. Aber Anpassungen werden in der Iteration nicht gesehen, dies könnte für die Benutzer verwirrend sein (undichte Abstraktion).

Ich könnte Sprachen/Bibliotheken vorstellen, die irgendwelche dieser Möglichkeiten mit gleichem Verdienst implementieren.

1

Viele kompilierte Sprachen implementieren "for" -Schleifen mit der Annahme, dass die Anzahl der Iterationen einmal beim Start der Schleife (oder besser noch, der Kompilierzeit) berechnet wird. Dies bedeutet, dass wenn Sie den Wert der Variablen "to" innerhalb der Schleife "for i = 1 to x" ändern, wird die Anzahl der Iterationen nicht geändert. Dies ermöglicht eine Vielzahl von Schleifenoptimierungen, die sehr wichtig sind, um Anwendungen mit Zahlenverarbeitung zu beschleunigen.

Wenn Sie diese Semantik nicht mögen, sollten Sie stattdessen das Konstrukt "while" der Sprache verwenden.

Beachten Sie, dass C und C++ in dieser Sicht der Welt keine richtigen "for" -Schleifen haben, sondern nur "while" -Schleifen.

Verwandte Themen