Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi IEnumerable rückwärts durchlaufen (https://www.delphipraxis.net/177099-ienumerable-rueckwaerts-durchlaufen.html)

Der schöne Günther 16. Okt 2013 09:45

Delphi-Version: XE2

IEnumerable rückwärts durchlaufen
 
Meine Hausaufgaben habe ich nicht wirklich gemacht,
Delphi-Quellcode:
IEnumerable
bzw.
Delphi-Quellcode:
IEnumerator
habe ich mir noch nicht wirklich im Detail angesehen.

Ich habe beispielsweise eine generische Liste. Ich iteriere mit einem "for ... in" darüber. Ich möchte jetzt aber nicht "vorwärts" sondern "rückwärts" über die Liste rutschen. Wie macht der Profi das? Oder gibt es vielleicht einen Standard "Rückwärts"-Enumerator den ich irgendwie verwenden kann?

Direkt (etwas unleserlich) anonym die drei IEnumerator-Methoden zu implementieren geht wahrscheinlich nicht und bläht den Code wohl zu sehr auf...

Bernhard Geyer 16. Okt 2013 09:57

AW: IEnumerable rückwärts durchlaufen
 
Das geht mit IEnumerable nicht.
MS hat das als nur nach vorne durchlaufbare Liste definiert. Siehe http://msdn.microsoft.com/de-de/libr...=vs.80%29.aspx

Aber was ist der Sinn davon das Rückwärts zu durchlaufen?

Union 16. Okt 2013 10:04

AW: IEnumerable rückwärts durchlaufen
 
Du kannst die Liste vor der Verarbeitung "umdrehen".

Der schöne Günther 16. Okt 2013 10:10

AW: IEnumerable rückwärts durchlaufen
 
Die strikte Vorschrift von "vorwärts" lese ich auch aus der .NET-Doku jetzt nicht heraus. Wenn ich es auf die Schnelle richtig sehe, kann ich den Enumerator, den bsp. eine stinknormale TList zurückgibt, nicht zur Laufzeit ändern, oder? Sonst hätte ich mir ja für den Fall meinen eigenen "Spaß-Enumerator" basteln können...

Die Liste mit Reverse() umzudrehen ist eine gute Idee. Nur leider werkelt da keine Magie im Hintergrund, da wird ja physikalisch wirklich jeder Eintrag mit seinem Gegenstück vertauscht:
Delphi-Quellcode:
procedure TList<T>.Reverse;
var
  tmp: T;
  b, e: Integer;
begin
  b := 0;
  e := Count - 1;
  while b < e do
  begin
    tmp := FItems[b];
    FItems[b] := FItems[e];
    FItems[e] := tmp;
    Inc(b);
    Dec(e);
  end;
end;
Meine Motivation war eigentlich aus Geschwindigkeitsgründen nicht ständig mit einem schrumpfenden Zahlen-Index in die Liste zu greifen sondern den Cursor des Enumerators zu nutzen. Ein Umdrehen der Liste ist zwar wirklich elegant, dauert aber wohl zu lange...

Union 16. Okt 2013 10:20

AW: IEnumerable rückwärts durchlaufen
 
Du könntest das auch in ein Objekt kapseln und eine revertete (wat'n Wort) "Schattenliste" mitführen. Die könntest Du dann entsprechend pflegen. Dafür dauert dann das Add länger ...

Mikkey 16. Okt 2013 10:25

AW: IEnumerable rückwärts durchlaufen
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1232156)
Die strikte Vorschrift von "vorwärts" lese ich auch aus der .NET-Doku jetzt nicht heraus.

Es ist auch keine Vorschrift, sondern die ergibt sich daraus, dass ein IEnumerable zwar eine implizite aber keine definierte Reihenfolge hat.

Enumeriert man die Werte eines Dictionarys, kommen die in irgendeiner Reihenfolge. Dadurch macht auch das Umkehren der Reihenfolge keinen Sinn.

Es gibt andere Interfaces, die auf definierte Reihenfolgen Rücksicht nehmen.

Medium 16. Okt 2013 10:45

AW: IEnumerable rückwärts durchlaufen
 
Ich habe "for .. in" schon immer mehr wie eine Collection verstanden. Also eine lose Ansammlung von gleichartigen Daten, die prinzipbedingt keiner Reihenfolge angehören. Wenn ich geordnete Listen nutze, bin ich daher immer beim "for i := 0 to MAX" geblieben, einfach weil es meinem Verständnis eher entsprach.

Der schöne Günther 16. Okt 2013 11:13

AW: IEnumerable rückwärts durchlaufen
 
Jetzt fing ich gerade an mich zu wundern, warum der Enumerator eines TStack auch vorwärts läuft, gerade hier wäre doch ein "Abräumen" logisch.

Aber dann fiel mir auch auf, dass der indizierte Zugriff überhaupt so abläuft, wie ich dachte: Ich dachte, TList sei eine klassische verkettete Liste und bei jedem Zugriff läuft er ganz von Anfang an so lange, bis er oft genug zum nächsten Element gesprungen ist. Bei großen Listen weiter hinten wäre das ja der Tod. Stattdessen ist das ja einfach nur ein Array!
Das erklärt auch, was Capacity bedeutet.

Wieder ein weiteres Mysterium geklärt. Die Welt ist gut.

Stevie 22. Okt 2013 11:59

AW: IEnumerable rückwärts durchlaufen
 
Eventuell als Zusatzinfo noch:

es gibt bestimmte IEnumerable Methoden, die verzögert ausgeführt werden und andere direkt.
Verzögerte Ausführung heißt, dass beim Durchlaufen erst die Elemente der Quelle durchlaufen werden (und das auch nur 1mal für einen kompletten Durchlauf) - z.B. Where oder Take

Einige Operationen können das nicht - zum Beispiel Reverse. Hierbei ist die Implementierung in .Net so, dass die Quelle ausgelesen und in ein Array gepackt wird. Dieses wird dann vom letzten bis zum ersten Element zurückgegeben.

Wenn man beachtet, dass hinter IEnumerable auch theoretisch eine unendliche Menge stecken kann, sieht man, dass bestimmte Operationen damit keinen Sinn machen würden.

Für eine for in Schleife spielt auch der Enumerator eine Rolle, welcher einen State hat - in dem Falle einer verketteten Liste könnte er also problemlos das aktuelle Element wissen, so dass du keinen Schlemiel hast.

Furtbichler 22. Okt 2013 19:02

AW: IEnumerable rückwärts durchlaufen
 
Zitat:

Zitat von Stevie (Beitrag 1232728)
...so dass du keinen Schlemiel hast.

:thumb: Man lernt nie aus.


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:56 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