![]() |
Löschen in einer "for in" Schleife
Hallo,
ich stehe öfters mal vor dem Problem, dass ich eine Liste habe, und Einträge daraus löschen möchte:
Delphi-Quellcode:
Das ganze kann aber zu komischen Effekten führen - zum Beispiel wird bei mir jetzt gerade ein Eintrag übersprungen. Vielleicht kommt der Iterator nicht damit zurecht, wenn der aktuelle Eintrag aus der Liste gelöscht wird.
var
Eintrag: TMeinEintrag; Liste: TObjectList<TMeinEintrag>; // ... for Eintrag in Liste do begin if Bedingung(Eintrag) then begin Liste.Remove(Eintrag); end; end; - Könnt ihr bestätigen, dass obiges Beispiel zu Fehlern führen kann? - Wie löscht ihr bestimmte Einträge aus einer Liste? Eine "for I := Count - 1 downto 0"-Schleife möchte ich vermeiden. Grüße Dominik |
AW: Löschen in einer "for in" Schleife
Das problem ist, daß der Standard-Enumerator nur den Index und das Ende kennt.
Er zählt einfach nur blind hoch und weiß nicht, daß du etwas löschst. siehe TObjectList.GetEnumerator (das ist der Enumerator, welchen For-In nimmt, wenn du selbst Keinen explizit übergibst) Die einzigen Lösungen sind da: - kein For-In, sondern eine While- oder eine For-Downto-Schleife nutzen - einen eigenen Enumerator nutzen - - entweder muß der auch rückwärts laufen - - oder er listet erst alles auf, merkt sich das und geht dann seine Liste durch - wenn deine TList eine ToArray-Funktion hast, dann läßt du die Liste in ein Array umwandeln und läufst dann mit dem Standard-Enumerator der Arrays über die Kopie, wobei das Array von deinem Löschen auch nichts weiß und demanch alles von seiner Kopier dir presentiert. [add] die generiesche TObjectList<T> geht auf TList<T> und die hat ein ToArray
Delphi-Quellcode:
for Eintrag in Liste.ToArray do
Du kannst Emba auch fragen, ob die das Löschen in dem Standardenumerator berücksichtigen. (dürfte mit zwei/drei Zeilen Quellcode möglich sein) |
AW: Löschen in einer "for in" Schleife
Die einfachste Lösung ist die zuletzt genannte:
Delphi-Quellcode:
for Eintrag in Liste.ToArray do
begin if Bedingung(Eintrag) then begin Liste.Remove(Eintrag); end; end; Zitat:
|
AW: Löschen in einer "for in" Schleife
Zitat:
Da eine For-In-Enumeration in der Umsetzung allgemeingültig sein muss, würde ich mich nie darauf verlassen, wie ein Iterator umgesetzt ist. D.h.: Löschen in Iterator: Nee. Und deshalb sollte die Remove-Implementierung in der Liste sofort (fail-fast) eine Exception werfen, wenn ein Enumerator aktiv ist. So wie ich das hier lese, scheint das bei Delphi (mal wieder) nur halbherzig, d.h. gar nicht umgesetzt worden zu sein. Oder irre ich mich? |
AW: Löschen in einer "for in" Schleife
Zitat:
Delphi-Quellcode:
Ist aber kein guter Programmierstil und birgt etliche Fallen. Deshalb: In DataSets immer nur mit Next, Prior, First und Last navigieren und beim Durchiterieren auf DataSet.Eof prüfen.
Dataset.Last;
for i := 1 to Dataset.RecordCount do begin DataSet.RecNo := i; ... end; |
AW: Löschen in einer "for in" Schleife
Hey danke für eure Antworten :thumb:
Das mit dem .ToArray gefällt mir gut (und es klappt sogar :-D). Das erstellt zwar eine Kopie der Liste, aber das ist in diesem Fall vertretbar. Zitat:
|
AW: Löschen in einer "for in" Schleife
Wenn Du unbedingt das for .. in - Konstrukt verwenden willst, legst Du halt eine Löschliste an, in die Du alle zu löschenden Kandidaten übernimmst und nach vollständigem Duchlauf diese Kandidaten gezielt löschst.
In C# führt Dein Vorgehen regelmäßig zu einer Exception. Dort ist der Umweg über den Index i.A. nicht möglich, deshalb ist der obige ein häufig beschrittener Weg. |
AW: Löschen in einer "for in" Schleife
Zitat:
Code:
Da braucht man noch nicht einmal mehr Kommentare.
foreach (var item in myEnumerable.Where(ItemIsNotValidAnymore))
{ myEnumerable.Remove(item); } ... bool ItemIsNotValidAnymore(MyEnumerableElement item) { ... } |
AW: Löschen in einer "for in" Schleife
Zitat:
|
AW: Löschen in einer "for in" Schleife
Zitat:
Delphi-Quellcode:
Oder findest Du die for-Schleife etwa 'old-school'? Den Umweg über ein Array zu gehen ist ja auch nicht gerade direkt, kurz und knapp, oder? Wenn Du das lesbar machen willst, dann benutze Refactoring;
for i:=Liste.Count-1 downto 0 do
if Bedingung(Eintrag[i]) Then Liste.Delete(i);
Delphi-Quellcode:
Beim Lesen des Codes kann man ja wohl nicht anders, als zu lesen, was dort passiert. Da muss man noch nicht einmal großartig in die Routine reinspringen, weil das ja im Kontext der o.g. Routine sekundär sein dürfte.
...
LoescheBestimmteElementeAusDer(Liste); ...
Delphi-Quellcode:
Procedure LoescheBestimmteElementeAusDer(Liste : TListe);
var i : Integer; Begin for i:=Liste.Count-1 downto 0 do if Bedingung(Eintrag[i]) Then Liste.Delete(i); End; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:43 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 by Thomas Breitkreuz