Entwickler-Ecke

Algorithmen, Optimierung und Assembler - [TStrings] doppelte Einträge entfernen


Jakob Schöttl - Fr 14.07.06 17:51
Titel: [TStrings] doppelte Einträge entfernen
Hallo,

Ich will aus meiner ListBox alle doppelten einträge entfernen. Zuerst wollte ich folgenden Algorithmus nehmen, also einen zeiger auf einen eintrag, und alle anderen nachfolgenden einträge auf gleichheit überprüfen, wenn gleich löschen:

Delphi-Quelltext
1:
2:
3:
4:
  for n := 0 to ListBox1.Items.Count -2 do
    for i := (n + 1to ListBox1.Items.Count -1 do
      While ListBox1.Items.Strings[n] = ListBox1.Items.Strings[i] do
        ListBox1.Items.Delete(i);


Aber da kommt immer der Fehler, dass ich das Maximum überschreite (Exception).

Vielleicht denken sich manche: So ein depp, das ist doch klar, weil der Fehler an meinem Code liegt!
Aber ich weiß leider nicht woran der Fehler liegt. Kann es sein, dass in einer for-Schleife der Endwert, in meinem Fall "ListBox1.Items.Count ...", nicht aktuellisiert wird, sondern immer gleich bleibt?

Ich wollte als alternative folgendes nehmen: alle Duplikate von Einträge werden auf '' gesetzt, und anschließend werden alle '' gelöscht.
Das ist zwar nicht die optimale lösung. Ich wollte es dann also so machen:

Delphi-Quelltext
1:
2:
3:
4:
for n := 0 to ListBox1.Items.Count -2 do
    for i := (n + 1to ListBox1.Items.Count -1 do
      if ListBox1.Items.Strings[n] = ListBox1.Items.Strings[i] then
        ListBox1.Items.strings[i] := '';


Aber Hilfe!! Nun hängt er in einer Endlos-Schleife! Warum?

Ich hoffe wirklich ihr könnt mir helfen.


mkinzler - Fr 14.07.06 18:08

Zitat:
Kann es sein, dass in einer for-Schleife der Endwert, in meinem Fall "ListBox1.Items.Count ...", nicht aktuellisiert wird, sondern immer gleich bleibt?
Ja, deshalb wäre es besser eine downto-Forschelife zu nehmen.


Marco D. - Fr 14.07.06 21:46


Delphi-Quelltext
1:
2:
3:
for n := listbox1.items.count-2 downto 0 do
begin
...

Der Rest müsste auch noch angepasst werden. Du musst die Liste also nicht von vorne, sondern von hinten durchgehen ;)


Blackheart666 - Fr 14.07.06 23:30


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TForm1.Button1Click(Sender: TObject);
var
  i,j : integer;
begin
  i := 0;
  while i <= ListBox1.Items.count - 2 do
  begin
    for j := i + 1 to ListBox1.Items.count - 1 do
    begin
      if ListBox1.Items[i] = ListBox1.Items[j] then
      begin
        dec(i);
        ListBox1.Items.delete(j);
        break;
      end;
    end;
    inc(i);
  end;
end;


Jakob Schöttl - Sa 15.07.06 00:08

Vielen Dank, der QuellText hat gleich funktioniert,
aber eine Frage hab ich zu den beiden Vorschlägen von marco und mkinzler: Wenn man also runterzählt, und es werden mehr als ein Eintrag gelöscht, dann beinhaltet doch die äußere schleife wieder eine Variable, die auf einen String zeigt, der nicht existiert?


mkinzler - Sa 15.07.06 07:06

Zitat:
aber eine Frage hab ich zu den beiden Vorschlägen von marco und mkinzler: Wenn man also runterzählt, und es werden mehr als ein Eintrag gelöscht, dann beinhaltet doch die äußere schleife wieder eine Variable, die auf einen String zeigt, der nicht existiert?
Es kommt darauf an, welche Logik verwendet wird. Ich würde wenn eine Übereinstimmung gefunden wird, immer das Vergleichselement löschen, dann ist sichergestellt, das pro Durchlauf immer nur ein Element eleminiert wird. Er entscheidet dann also nur ob das Element mit dem aktuellen Index gelöscht wird oder nicht.


Jakob Schöttl - Sa 15.07.06 07:33

aja, wenn man also nur das 1. Vergleichselement löscht, dann dauert es zwar ein bisschen länger, teoretisch, aber dann gibts wenigstens keine Exceptionen

Danke nochmal!


mkinzler - Sa 15.07.06 07:35

Das dütfte auch nicht länger dauern, da die Anzahl der Schleifenduchläufe und die Anzahl der Deletes gleich bleibt. Ich würde auch nur eine Schleife nehmen und per IndexOf auf doppelte Einträge vergleichen.