Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   For xx In xxx Schleife rückwärts? (https://www.delphipraxis.net/178739-xx-xxx-schleife-rueckwaerts.html)

milos 24. Jan 2014 11:21

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

Union 24. Jan 2014 11:24

AW: For xx In xxx Schleife rückwärts?
 
Mit
Delphi-Quellcode:
for i := 10 downto 1 do

jaenicke 24. Jan 2014 11:27

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.

milos 24. Jan 2014 11:37

AW: For xx In xxx Schleife rückwärts?
 
Ok, danke für den Tipp :)

Werde es mit downto lösen. ^^

MfG

Union 24. Jan 2014 11:42

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]
http://docwiki.embarcadero.com/RADSt...nd_Anweisungen

Es gibt nur noch eine Riesenseite mit allen Anweisungen.
[/edit]

himitsu 24. Jan 2014 12:02

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.

Stevie 24. Jan 2014 14:22

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von jaenicke (Beitrag 1245162)
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.

Zitat:

Zitat von himitsu (Beitrag 1245177)
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.

Das ist nicht ganz korrekt. Für einen Menge Elemente, die einen Index Zugriff bieten, liefert auch ein for-in die Elemente in der gleichen Reihenfolge zurück wie mit einem for-to (nicht for-downto!). Durch die Möglichkeit, selber den Enumerator für eine for-in Schleife zu schreiben, verbietet natürlich keiner, die Elemente in einer komplett anderen Reihenfolge (oder sogar non deterministisch) zurückzuliefern (was aber imho schon an Sabotage grenzt).

Medium 24. Jan 2014 15:08

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Stevie (Beitrag 1245201)
(oder sogar non deterministisch [..] was aber imho schon an Sabotage grenzt).

Sehe ich anders. Diese Art der Schleife ist ja gerade darüber definiert, dass sie eine ungeordnete Menge an Elementen iteriert. Würde man sich in einer for..in-Schleife auf ein festgelegtes Iterationsverhalten verlassen, so wäre das extrem schlecht selbstdokumentierender Code. Ein for..to dagegen zeigt direkt eindeutig eine Laufrichtung inkl. Grenzen an. Es hat daher auch durchaus seinen wohl überlegten Sinn, dass beide Konstrukte nebeneinander existieren.
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.

Stevie 24. Jan 2014 15:45

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.

Furtbichler 24. Jan 2014 16:30

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Stevie (Beitrag 1245216)
Für arrays ist es so implementiert, dass ein for-in einem for-to entspricht.

Reiner Zufall. Heute so, morgen anders (Rückwärtszählen geht vielleicht schneller, Speicher ist nicht mehr linear aufgebaut, wer weiß das schon).
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.

jaenicke 24. Jan 2014 16:40

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Stevie (Beitrag 1245216)
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.

Definiert ist dieses Verhalten für Arrays:
http://docwiki.embarcadero.com/RADSt...nd_Anweisungen
Zitat:

Array-Ausdrücke können sich auf ein- oder mehrdimensionale Arrays, Arrays mit fester Länge oder dynamische Arrays beziehen. Das Array wird in aufsteigender Reihenfolge durchlaufen, beginnend mit der unteren Array-Grenze bis zur Array-Größe minus eins.
Trotzdem passt die Syntax nicht dazu das vorauszusetzen. Das ist genauso unsauber wie bei AnsiStrings die Länge als Größe in Byte anzunehmen oder die Größe eines Pointers als Größe eines Integers anzunehmen oder...
Schlicht weil es absolut keinen Sinn macht, wenn man auf bestimmte Indizes zugreifen will (eine bestimmte Reihenfolge eben) diese nicht zu benutzen...

Panthrax 24. Jan 2014 17:06

AW: For xx In xxx Schleife rückwärts?
 
Delphi-Quellcode:
type
  IEnumerable<T> = interface(IEnumerable)
    ///   <summary>
    ///     Inverts the order of the elements in a sequence.
    ///   </summary>
    function Reversed: IEnumerable<T>;
  end;
Quelle: Spring.Collections.pas:250

Delphi-Quellcode:
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.
Ausgabe:
Code:
Vier.
Drei.
Zwei.
Eins.

Medium 24. Jan 2014 22:56

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.

jfheins 24. Jan 2014 23:12

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?

jaenicke 25. Jan 2014 08:36

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.

Panthrax 25. Jan 2014 13:48

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:

Zitat von milos (Beitrag 1245159)
Ist es möglich in eine For-in-Schleife rückwärts laufen zu lassen, ohne dass man in der Liste etwas dreht?


Furtbichler 25. Jan 2014 13:55

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Panthrax (Beitrag 1245300)
Einträge in einer Reihenfolge anzuordnen gehört sowohl zum Wesen einer Liste als auch zum Wesen einer Aufzählung.

Nö. Nimm Dir ein RDBMS und verwende einen serverseitigen Cursor ohne explizite Ordnung (d.h. ein 'SELECT' ohne 'ORDER BY'): Auf diese Reihenfolge kannst Du dich nicht verlassen.

Anderes Beispiel:

Delphi-Quellcode:
MyList.Add(1);
MyList.Add(3);
MyList.Add(2);
For element in MyList do
  Writeln(element);
Preisfrage: In welcher Reihenfolge werden die Elemente ausgegeben? :lol:

Panthrax 25. Jan 2014 14:30

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Furtbichler (Beitrag 1245303)
Nö. Nimm Dir ein RDBMS und verwende einen serverseitigen Cursor ohne explizite Ordnung (d.h. ein 'SELECT' ohne 'ORDER BY'): Auf diese Reihenfolge kannst Du dich nicht verlassen.

Was ist in diesem Beispiel die Liste? Das Ergebnis einer Select-Abfrage ist sehr wohl eine Liste, und wiederholtes Aufzählen ihrer Einträge ergäbe eine immer gleiche Reihenfolge. Eine neue Select-Abfrage erstellt eine neue Liste. Ein Cursor ist weder eine Liste, noch bedeutet "Cursor", dass er in einer navigiert.

Zitat:

Zitat von Furtbichler (Beitrag 1245303)
Delphi-Quellcode:
MyList.Add(1);
MyList.Add(3);
MyList.Add(2);
For element in MyList do
  Writeln(element);
Preisfrage: In welcher Reihenfolge werden die Elemente ausgegeben? :lol:

Code:
1
3
2
Eine andere Reihenfolge ist ein Fehler.

jaenicke 25. Jan 2014 15:46

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Panthrax (Beitrag 1245312)
Eine andere Reihenfolge ist ein Fehler.

Delphi-Quellcode:
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;
Das heißt es ist auch ein Fehler, dass dort nicht Eins, Zwei, Drei herauskommt?

for..in heißt nur "gehe alle Elemente durch". Nicht mehr und nicht weniger.

Panthrax 25. Jan 2014 16:01

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von jaenicke (Beitrag 1245323)
Das heißt es ist auch ein Fehler, dass dort nicht Eins, Zwei, Drei herauskommt?

Nein, kein Fehler, es ist keine Liste.

Die For-in-Schleife geht alle Elemente einer Aufzählung durch. Und das Aufzählen einer Liste geschieht von vorn nach hinten.

jaenicke 25. Jan 2014 16:07

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.

himitsu 25. Jan 2014 16:34

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.

Panthrax 25. Jan 2014 17:09

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von jaenicke (Beitrag 1245327)
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.

Richtig! Vielleicht noch einmal zur Erinnerung (und unter Berücksichtigung der Bindung durch den Compiler), der Aufruf einer Methode wird konzeptionell zurückgeführt auf den Aufruf einer Routine mit dem Objekt als erstem Parameter:
Delphi-Quellcode:
Objekt.Methode(Argument);
Methode(Objekt, Argument);
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.

Anderes Beispiel:
Delphi-Quellcode:
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.
Ausgabe:
Code:
Aufzählung 1
Eins.
Eins.
Zwei.
Drei.
Vier.
Drei.
Aufzählung 2
Zwei.
Drei.
Eins.
Vier.
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.
Delphi-Quellcode:
Add
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
Delphi-Quellcode:
Enumerate
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
Delphi-Quellcode:
TDictionary<...>
-Beispiel von oben;
Delphi-Quellcode:
IDictionary<NativeInt, String>
und
Delphi-Quellcode:
IList<TPair<NativeInt, String>>
sind eben unterschiedliche Typen, auch wenn beide einen
Delphi-Quellcode:
IEnumerator<TPair<NativeInt, String>>
anbieten.

Furtbichler 25. Jan 2014 18:40

AW: For xx In xxx Schleife rückwärts?
 
Du bist ja ein richtiger Fachmann. :thumb: :lol:
Zitat:

Zitat von Panthrax (Beitrag 1245312)
Was ist in diesem Beispiel die Liste?

Die Tabelle.
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:

Eine andere Reihenfolge ist ein Fehler.
Ach, echt? Hatte ich erwähnt, das es sich um eine TSortedList handelt (1,2,3). :-D oder eine TLinguisticSortedList? (3,1,2). Oder eine Hashmap? Oder. Oder. Oder.
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.

Medium 25. Jan 2014 18:40

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.

Panthrax 25. Jan 2014 19:42

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Furtbichler (Beitrag 1245349)
Zitat:

Eine andere Reihenfolge ist ein Fehler.
Ach, echt? Hatte ich erwähnt, das es sich um eine TSortedList handelt (1,2,3). Oder eine TLinguisticSortedList? (3,1,2). Oder eine Hashmap? Oder. Oder. Oder.

Nein, hatten Sie nicht. Was nicht dasteht kann nicht bewertet werden. Im übrigen widersprechen Sie auf ihren Umwegen ja auch nicht. Meine vorigen Beiträge sind auch ausreichend Antwort bis hierhin. Vielleicht finden Sie ja wirklich bestätigend viele Leute in Ihrem Umfeld, die Sie bitten können einmal aufzuzählen was auf Ihrer Einkaufsliste steht, und die dann wirklich jedes Mal die Liste anders rauf- und runterspringen. Ich würde ja meinen sie würden es einfach von vorn nach hinten durchlesen. In der Tat, so schwer kann das doch nicht sein.

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:

Zitat von Medium (Beitrag 1245350)
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.

Stichwort: Produktivität. - Ich bin raus.

BUG 26. Jan 2014 23:41

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:

Medium 27. Jan 2014 10:10

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:
for Item in List.ForwardIterator do
o.ä. Das würde sich wieder selbst dokumentieren wie der Index, ohne den von dir genannten Nachteil.

Stevie 27. Jan 2014 13:49

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Furtbichler (Beitrag 1245223)
Zitat:

Zitat von Stevie (Beitrag 1245216)
Für arrays ist es so implementiert, dass ein for-in einem for-to entspricht.

Reiner Zufall. Heute so, morgen anders (Rückwärtszählen geht vielleicht schneller, Speicher ist nicht mehr linear aufgebaut, wer weiß das schon).
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.

Zu glauben, dass sich das Verhalten einer for-in Schleife für ein Array ändert ist eher der große Käse. Die Compiler Optimierung des rückwärts zählens auf 0 bei einer for-to Schleife wird auch nur vorgenommen, wenn der Index in der Schleife nicht benötigt wird und dementsprechend die Logik des Programms nicht verändert wird. Das trifft auf eine for-in Schleife wohl auch nur dann zu, wenn man im Schleifenrumpf nix mit der Laufvariable macht. Wobei dann die Reihenfolge auch Rille wäre.

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 :)

himitsu 27. Jan 2014 13:59

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Stevie (Beitrag 1245517)
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 :)

Das dürfte im Delphi vermutlich auch auf TStack und TQueue zutreffen (solange man sie nicht als FIFO benutzt).
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:)

Stevie 27. Jan 2014 14:26

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von himitsu (Beitrag 1245519)
Zitat:

Zitat von Stevie (Beitrag 1245517)
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 :)

Das dürfte im Delphi vermutlich auch auf TStack und TQueue zutreffen (solange man sie nicht als FIFO benutzt).
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:)

Nö, sowohl TStack<T> als auch TQueue<T> werden ganz simpel mit einem Array implementiert und sind somit deterministisch enumerierbar (beides von TEnumerable<T> abgeleitet). Da sich hier im Gegensatz zu einer mit Binärheap implementierten Prioritätsqueue die Elemente bei Einfügen und Entfernen nicht im Array verschieben, gibts kein Problem - außer dass der Stack Enumerator die Elemente umgekehrt ausgibt, im Gegensatz zu einem Pop bis Stack leer.

Und nein, ein Enumerator darf niemals die Datenmenge verändern!

himitsu 27. Jan 2014 14:30

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Stevie (Beitrag 1245529)
Und nein, ein Enumerator darf niemals die Datenmenge verändern!

War auch nur eine Überlegung.


"gehe alle Elemente durch", so ala "poppe" Alles aus der Liste raus, bis sie leer ist.

Medium 27. Jan 2014 21:08

AW: For xx In xxx Schleife rückwärts?
 
Zitat:

Zitat von Stevie (Beitrag 1245517)
Zu glauben, dass sich das Verhalten einer for-in Schleife für ein Array ändert ist eher der große Käse.

Ebenso, wie "Integer" immer brav mitgewachsen ist (obwohl es da sogar ursprünglich so garantiert wurde), gelle? ;)


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