![]() |
For xx In xxx Schleife rückwärts?
Hallo
Ist es möglich in eine For In Schleife rückwärts laufen zu lassen, ohne dass man in der Liste etwas dreht? MfG |
AW: For xx In xxx Schleife rückwärts?
Mit
Delphi-Quellcode:
for i := 10 downto 1 do
|
AW: For xx In xxx Schleife rückwärts?
Eine for..in Schleife ist per Definition dafür gedacht, dass man die Elemente in einer beliebigen Reihenfolge durchläuft. Dass sie aufgrund der aktuellen Implementierung eine bestimmte Reihenfolge haben, mag sein, ist aber nicht garantiert.
Deshalb: Wenn die Reihenfolge wichtig ist, niemals for..in nutzen. Theoretisch kann man das zwar mit einem eigenen Enumerator sicherstellen, aber das ist nicht gerade sauber... Besser ist es über den Index und for..downto zu gehen und den aktuellen Eintrag selbst ggf. in eine Variable zu speichern um ihn nicht immer wieder aus der Liste abrufen zu müssen. |
AW: For xx In xxx Schleife rückwärts?
Ok, danke für den Tipp :)
Werde es mit downto lösen. ^^ MfG |
AW: For xx In xxx Schleife rückwärts?
Dabei ist mir aufgefallen, dass die aktuelle Online-Dokumentation die Delphi-Anweisungen überhaupt nicht beinhaltet. Selbst wenn man die Anweisungen kennt und direkt danach sucht, landet man immer im entsprechenden (und unvollständigen) C++ Teil.
[edit] ![]() Es gibt nur noch eine Riesenseite mit allen Anweisungen. [/edit] |
AW: For xx In xxx Schleife rückwärts?
Wobei die FOR-IN-Schleife selber nichts mit der Reihenfolge zu tun hat.
Sie läuft einfach nur von vorhne nach hinten alle einträge durch, bis der Enumerator sagt, daß es nichts mehr gibt. Die Reihenfolge der Daten vom Enumerator sind nicht vorgeschrieben, womit es also kein Problem ist, wenn man sich einen Enumerator erstellt, welcher die Daten in umgekehrter Reihenfolge liefert. |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Zitat:
|
AW: For xx In xxx Schleife rückwärts?
Zitat:
Ein for..in mit einer Abhängigkeit von einer Reihenfolge der Aufzählung würde ich daher sogar als groben Fehler ansehen, da es eine wichtige Sache stark verschleiert. |
AW: For xx In xxx Schleife rückwärts?
Für arrays ist es so implementiert, dass ein for-in einem for-to entspricht.
Für alles andere (wenn ich jetzt grad außer Arrays nix vergessen habe) ist die Implementierung des enumerators, welcher über die GetEnumerator Funktion zurückgeliefert wird, dafür zuständig, welche Reihenfolge angewandt wird. Da die Delphi Dokumentation ja nicht so ausführlich wie beispielsweise die MSDN ist, kann ich gerade nicht sagen, ob dort für TList<T>, TStrings oder sonstiges, was ein GetEnumerator (also for-in tauglich ist) implementiert, dokumentiert wurde, in welcher Reihenfolge, die Elemente zurückgeliefert werden. In allen mir bekannten Fällen, in denen intern ein Array zur Datenhaltung dient, ist hier das gleiche der Fall, wie oben bereits erwähnt (equivalent zu for-to). Der primäre Unterschied zwischen einem for-in und einem for-to ist der Indexzugriff, den man bei einem for-in nicht hat bzw nicht benötigt, von daher sind die beiden Konstrukte in keinem Fall komplett redundant. Ebenfalls kann ich mit einem for-in auch locker über eine endlose Menge iterieren oder über eine, deren Anzahl beim Start noch nicht feststeht. |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Sich darauf zu verlassen, wie etwas implementiert ist, ist -mit Verlaub- ganz großer Käse. Eigentlich darf man in einer For-In Schleife auch keine Änderungen an der der laufenden Enumeration zugrundeliegenden Datenstruktur vornehmen (auf Gut Deutsch: Die Liste verändern). Aber da ist Delphi wohl nicht so safe. |
AW: For xx In xxx Schleife rückwärts?
Zitat:
![]() Zitat:
Schlicht weil es absolut keinen Sinn macht, wenn man auf bestimmte Indizes zugreifen will (eine bestimmte Reihenfolge eben) diese nicht zu benutzen... |
AW: For xx In xxx Schleife rückwärts?
Delphi-Quellcode:
Quelle:
type
IEnumerable<T> = interface(IEnumerable) /// <summary> /// Inverts the order of the elements in a sequence. /// </summary> function Reversed: IEnumerable<T>; end; ![]()
Delphi-Quellcode:
Ausgabe:
program Project1;
{$AppType Console} {$R *.res} uses System.SysUtils, Spring.Collections, Spring.Collections.Lists; procedure Run; type T = String; var List: IList<T>; Item: T; begin List := TList<T>.Create; List.AddRange(['Eins.', 'Zwei.', 'Drei.', 'Vier.']); for Item in List.Reversed do WriteLn(Item); end; begin try Run; except on E: Exception do WriteLn(E.ClassName + ': ' + E.Message); end; if DebugHook <> 0 then ReadLn; end.
Code:
Vier.
Drei. Zwei. Eins. |
AW: For xx In xxx Schleife rückwärts?
Dass etwas geht heisst nicht gleich, dass es auch gut ist. Dass andere dieses etwas gemacht haben ebensowenig, da können jetzt Beispiele noch und nöcher kommen.
Man Verschleiert die Abhängigkeit von einer definierten Reihenfolge durch die Nutzung einer Operation auf einer prinzipiell unsortierten Menge. Dass sie es in der Praxis oftmals dennoch ist, ist nicht Bestandteil des Vorganges, und muss von keiner Implementierung garantiert werden, bzw. kann es in unterschiedlichen Implementierungen unterschiedlich gehandhabt werden. Und allein das würde mich immer wieder dazu motivieren in diesen Fällen for..to zu nutzen, zumal es erheblich besser dokumentiert. Mehr als warnen kann man leider nicht. |
AW: For xx In xxx Schleife rückwärts?
Oder noch besser: Man stelle sich einen zukünftigen Compiler vor, der merkt dass innerhalb der for-in Schleife keine Seiteneffekte auftreten. Und *wuppdi* werden alle 30 Iterationen gleichzeitig ausgeführt. (Bis der Delphi-Compiler das kann habe wir bestimmt 32-Kern CPUs in Laptops) Die Reihenfolge wäre dann nicht-deterministisch und hinge vom Scheduler ab.
Genial, wa? |
AW: For xx In xxx Schleife rückwärts?
Das würde ich jetzt nicht einmal als zu futuristisch ansehen, denn mit LLVM als Backend muss das ja nicht einmal der Delphi Compiler machen, sondern könnte es dort implementiert werden und einfach genutzt werden. Insofern könnte so etwas schneller kommen als man denkt.
|
AW: For xx In xxx Schleife rückwärts?
Einträge in einer Reihenfolge anzuordnen gehört sowohl zum Wesen einer Liste als auch zum Wesen einer Aufzählung. Es ist wenigstens intuitiv, zu erwarten, dass die Aufzählung einer Liste die Einträge in eben dieser Reihenfolge liefert - und dass diese Reihenfolge umgekehrt werden kann.
Sich dieser Intuition zu verweigern ist ein Fehler. Man kann Menschen auch unnötig verunsichern, wenn man gegen ihren gesunden Verstand redet. Es ist nicht die For-in-Anweisung, welche die Reihenfolge bestimmt, sondern der Aufzähler. Auch die Übersetzung der Schleife für parallele Ausführung wird diese Reihenfolge nicht ändern. Wenn festgestellt werden kann, dass derselbe Schleifenkörper mehrmals parallel ausgeführt werden kann, bedeutet das nur, dass die Bearbeitung unabhängig von der Aufzählungsreihenfolge ist. --------------- Zitat:
|
AW: For xx In xxx Schleife rückwärts?
Zitat:
Anderes Beispiel:
Delphi-Quellcode:
Preisfrage: In welcher Reihenfolge werden die Elemente ausgegeben? :lol:
MyList.Add(1);
MyList.Add(3); MyList.Add(2); For element in MyList do Writeln(element); |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Zitat:
Code:
Eine andere Reihenfolge ist ein Fehler.
1
3 2 |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Delphi-Quellcode:
Das heißt es ist auch ein Fehler, dass dort nicht Eins, Zwei, Drei herauskommt?
var
Test: TDictionary<Integer, String>; Current: TPair<Integer, String>; begin Test := TDictionary<Integer, String>.Create; try Test.Add(1, 'Eins'); Test.Add(2, 'Zwei'); Test.Add(3, 'Drei'); for Current in Test do ShowMessage(Current.Value); finally Test.Free; end; end; for..in heißt nur "gehe alle Elemente durch". Nicht mehr und nicht weniger. |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Die For-in-Schleife geht alle Elemente einer Aufzählung durch. Und das Aufzählen einer Liste geschieht von vorn nach hinten. |
AW: For xx In xxx Schleife rückwärts?
Eben. In der Benutzung ist es aber exakt gleich. Heißt: Man müsste bei der Betrachtung stets nachschauen von was denn die Klasse, die in einem Quelltext benutzt wird, abgeleitet ist, um beurteilen zu können, ob ein Quelltext macht was er soll.
Und das ist ein No-Go in sauberem Quelltext. |
AW: For xx In xxx Schleife rückwärts?
Aber wie am Beispiel des TList.Reversed, kann man die Funktion auch direkt am Quellcode dokumentieren.
Also wenn man eine bestimmre Reihenfolge benötigt, dann kann man auch einen passenden Enumerator auch direkt angeben. Wie z.B. einen rückwärttslaufenden Enumerator, oder Einen, welcher die Liste vorher cached, wenn man innerhalb der Schleife die Liste verändern möchte, oder einen Enumerator, welcher die Liste gefilltert durchläuft und nur bestimmte Einträge behandelt. |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Delphi-Quellcode:
Kein Parameter ohne Bedeutung: Das Objekt stellt einen Zusammenhang mit Daten her und die Klasse des Objekts stellt einen Zusammenhang mit Funktionen her. Stichwort: Polymorphie.
Objekt.Methode(Argument);
Methode(Objekt, Argument); Anderes Beispiel:
Delphi-Quellcode:
Ausgabe:
program Project1;
{$AppType Console} uses System.SysUtils, Spring.Collections, Spring.Collections.Lists, Spring.Collections.Sets; type T = String; procedure Enumerate(const Caption: String; const Enumerable: IEnumerable<T>); var Value: T; begin WriteLn(Caption); for Value in Enumerable do WriteLn(Value); end; procedure Run; var Collection1: IList<T>; Collection2: ISet<T>; Value: T; begin Collection1 := TList<T>.Create; Collection2 := THashSet<T>.Create; Collection1.Add('Eins.'); Collection1.Add('Eins.'); Collection1.Add('Zwei.'); Collection1.Add('Drei.'); Collection1.Add('Vier.'); Collection1.Add('Drei.'); for Value in Collection1 do Collection2.Add(Value); Enumerate('Aufzählung 1', Collection1); Enumerate('Aufzählung 2', Collection2); end; begin try Run; except on E: Exception do WriteLn(E.ClassName + ': ' + E.Message); end; if DebugHook <> 0 then ReadLn; end.
Code:
Das verdeutlicht vielleicht noch einmal auf andere Weise, dass das Objekt und seine Klasse bedeutsam sind für das, welche Funktion mit welchen Daten ausgeführt werden soll. Dieses Verhalten ist erwünscht und der wesentliche Grund dafür, warum wir Polymorphie nutzen. Bspw.
Aufzählung 1
Eins. Eins. Zwei. Drei. Vier. Drei. Aufzählung 2 Zwei. Drei. Eins. Vier.
Delphi-Quellcode:
ist für eine Liste eben anders definiert als für eine Menge. Gleichermaßen ist eine Aufzählung für eine Liste klar definiert, und kann durchaus von anderen Aufzählungen anderer Typen abweichen. Gleichsam sind beides Sammlungen und beide aufzählbar, was bei der Routine
Add
Delphi-Quellcode:
nützlich ist. Und eine Menge bietet eben keinen indizierten Zugriff auf ihre Elemente, der für eine For-to-Schleife benötigt wird. Er müsste erst künstlich geschaffen werden. Genauso bei dem
Enumerate
Delphi-Quellcode:
-Beispiel von oben;
TDictionary<...>
Delphi-Quellcode:
und
IDictionary<NativeInt, String>
Delphi-Quellcode:
sind eben unterschiedliche Typen, auch wenn beide einen
IList<TPair<NativeInt, String>>
Delphi-Quellcode:
anbieten.
IEnumerator<TPair<NativeInt, String>>
|
AW: For xx In xxx Schleife rückwärts?
Du bist ja ein richtiger Fachmann. :thumb: :lol:
Zitat:
Ein Enumerator hat genauso viel mit einer Liste zu tun wie ein Cursor mit einer Tabelle. Der Cursor zählt die Query auf, der Enumerator die Liste. Wo und wie ist denn die Reihenfolge definiert, wenn die nicht explizit festgelegt ist? Heute kommen die Daten so, morgen so. Glaubste nicht? Tja, dann fehlt dir was. Zitat:
Also nochmal, für Hausfrauen, zum Mitschreiben: Die Reihenfolge der Aufzählung ist implementierungsabhängig, mithin undefiniert (obwohl meistens deterministisch) und im Einzelfall durchaus heute anders als morgen. Sie darf auch nichtdeterministisch sein (RDBMS), d.h. jedesmal in einer anderen Reihenfolge. Der einzige Grund, weshalb das i.a. nicht der Fall ist, ist doch der, das es naheliegend ist, das ein Array oder eine Liste die Elemente mit einem Index aufzählt. Aber wie sieht es mit der Reihenfilge bei einer Hashmap aus? Oder einem Baum? Wie ist denn die Reihenfolge hier? Infix, Prefix, Postfix? Was ist mit einem ungerichteten Graphen? Trie? etc. etc. etc. Deshalb hat man doch gerade das gemeinsame IEnumerable-Paradigma, um die einzelnen Elemente wenigstens aufzählen zu können, auch Mengen ohne innere Ordnung. Mann, so schwer kann das doch nicht sein. |
AW: For xx In xxx Schleife rückwärts?
Code, bei dem ich erst die Klassenhierarchie studieren müsste um herauszufinden wie meine Schleife läuft (und dies relevant ist), würde ich dem Autor sowas von um die Ohren knallen, das glaubst du gar nicht. Das ist bewusstes torpedieren von Teamarbeit und Produktivität.
|
AW: For xx In xxx Schleife rückwärts?
Zitat:
Nun denn, wenn es darum geht Liste zu nennen, was keine ist, und Dinge nicht so zu implementieren, wie es ihr Name sagt, und man dabei Unsicherheit wider der Vernunft streut, während man beim Programmieren selbst immer wieder in die Defensive gerät - denn es könnte sich ja immer alles auch ein bisschen anders verhalten - dann sind wir beim Etikettenschwindel angekommen: Zitat:
|
AW: For xx In xxx Schleife rückwärts?
Im Grunde streitet ihr euch, ob ein foreach auf einem Iterator arbeitet (=> Reihenfolge hängt vom Iterator ab, kann je nach Art des Iterators bekannt oder unbekannt sein) oder auf einer Datenstruktur (=> Reihenfolge ist bei unbekannter Datenstruktur unbekannt, im Zweifelsfall Index benutzen). Mir ist die Iterator-Sichtweise lieber.
Was die Index-Fanatiker (SCNR) nicht berücksichtigen: Gerade der Zugriff durch den Index ist unter Umständen nicht wirklich effizient. Man denke nur mal an eine verkettete Liste: Der Index ist eigentlich überhaupt nicht interessant, man möchte nur einmal die Liste von vorne nach hinten durchlaufen. Trotzdem darf man jetzt Länge der Liste mal zu dem jeweils gesuchten Index laufen. Hurra, schon ist aus einer linearen eine quadratische Laufzeit geworden :thumb: Wenn ich einen bestimmten Iterator benutze/fordere, dann kann ich mich auf die Reihenfolge verlassen, die dieser garantiert. Die Anforderungen an den Iterator sollte man natürlich irgendwo dokumentieren :mrgreen: |
AW: For xx In xxx Schleife rückwärts?
Nettes Beispiel! Ich gebe zu, dass es hier tatsächlich ein Grenzfall ist. Und auch wenn ich bei verketteten Listen durchaus nicht die Nase rümpfen würde, wenn dort jemand "altbacken" mit einer while-Schleife und CurrentItem := CurrentItem.Next; durchrauscht, sehe ich eine potenzielle Vereinfachung durch for..in hier. In solch einem Fall würde ich mir dann aber schon einen explizit benutzten Iterator mit sinnvollem Namen wünschen, oder zumindest ein Wort dazu im Kommentar.
Delphi-Quellcode:
o.ä. Das würde sich wieder selbst dokumentieren wie der Index, ohne den von dir genannten Nachteil.
for Item in List.ForwardIterator do
|
AW: For xx In xxx Schleife rückwärts?
Zitat:
Was die Veränderung der durchlaufenden Struktur angeht ist die Implementierung in der Delphi RTL wirklich nicht sehr dolle. In Spring4d hingegen wird dir ein Enumerator mit einer Exception ins Gesicht springen, wenn du zwischendurch die zugrundelegende Datenmenge veränderst (analog zum Verhalten in .Net). Ich stimme den meisten hier zu, dass es gefährlich sein kann, anhand eines abstrakten Interfaces (IEnumerable<T>) auf ein Implementierungsdetail zu schließen. Deshalb würde ich in einem solchen Fall eher vorschlagen, ein weniger abstraktes zu benutzen. In Spring4d/.Net würde sich dort z.B. IList<T> anbieten. Dieses bietet direkten Indexzugriff und man kann sich sicher sein, dass implementierende Klassen den Enumerator auch in einer solchen Weise implementieren, dass die Liste von vorn nach hinten durchlaufen werden. Im übrigen macht das .Net Framework selber bei den diversen IEnumerable<T> extension methods implizite Annahmen über die Ausführung. Schaut euch einfach mal First, Last oder ElementAt an (welche intern eine Optimierung für den Fall haben, dass es sich um IList<T> handelt). Dass eine enumeration ein nicht erwartetes Ergebnis hat, habe ich erst kürzlich selbst erlebt, einfach mal eine PriorityQueue enumerieren und sich wundern, dass die Elemente eine andere Reihenfolge haben, als wenn man Dequeue aufruft, bis sie leer ist :) |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Also falls die überhaupt einen Enumerator haben. Und wenn, müsste der Enumerator, bei sowas, nicht sogar der Liste geleert werden? (jedes Element müsse trausgenommen werden, sobaldes verarbeitet wird :gruebel:) |
AW: For xx In xxx Schleife rückwärts?
Zitat:
Und nein, ein Enumerator darf niemals die Datenmenge verändern! |
AW: For xx In xxx Schleife rückwärts?
Zitat:
"gehe alle Elemente durch", so ala "poppe" Alles aus der Liste raus, bis sie leer ist. |
AW: For xx In xxx Schleife rückwärts?
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:15 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz