Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TStringList ignoriert doppelte Einträge nicht (https://www.delphipraxis.net/154324-tstringlist-ignoriert-doppelte-eintraege-nicht.html)

devidespe 6. Sep 2010 17:34

Delphi-Version: 2007

TStringList ignoriert doppelte Einträge nicht
 
Hi,

ich benutze Delphi 2007 Pro und versuche, eine StringList mit Einträgen zu füllen. Dabei sollen doppelt hinzugefügte Einträge ignoriert werden. Hier ein vereinfachter Auszug meines Codes:

Delphi-Quellcode:
var Liste : TStringList
    i : Byte;
begin
  Liste:=TStringList.Create;
 
  Liste.Sorted:=False;
  Liste.Duplicates:=dupIgnore;

  Liste.Add('Eintrag 1');
  Liste.Add('Eintrag 1');
  Liste.Add('Eintrag 1');

  for i:=0 to Liste.Count-1 do showmessage(Liste.Strings[i]);

  Liste.Free;
end;
Woran kann es liegen, dass die doppelten Einträge trotzdem vorhanden sind?

Matze 6. Sep 2010 17:38

AW: TStringList ignoriert doppelte Einträge nicht
 
Zitat:

Zitat von devidespe (Beitrag 1047854)
Delphi-Quellcode:
Liste.Sorted:=False;
Liste.Duplicates:=dupIgnore;
Woran kann es liegen, dass die doppelten Einträge trotzdem vorhanden sind?

Auszug aus der Hilfe:
Zitat:

Note: Duplicates does nothing if the list is not sorted.
Edit: Und zukünftig daran denken, Ressourcen-Schutzblöcke zu nutzen, damit auch im Fehlerfall der Speicher freigegeben wird:
Delphi-Quellcode:
Liste := TStringList.Create;
try
  // ...
finally
  Liste.Free; // oder: FreeAndNil(Liste);
end;

devidespe 6. Sep 2010 17:41

AW: TStringList ignoriert doppelte Einträge nicht
 
Okay, das hatte ich überlesen.

Gibt es keine Möglichkeit, dies ohne Listensortierung durchzuführen?

Matze 6. Sep 2010 17:42

AW: TStringList ignoriert doppelte Einträge nicht
 
Nur manuell, indem du vor dem Einfügen selbst in einer Schleife prüft, ob der Eintrag bereits enthalten ist.

Also grob aus dem Kopf:
Delphi-Quellcode:
Included := false;
for i := 0 to Liste.Count - 1 do
begin
  if Liste[i] = 'Eintrag 1' then
  begin
    Included := true;
    break;
  end;
end;

if not Included then
  Liste.Add('Eintrag 1');
Natürlich noch schön als Funktion/Methode verpacken und gut ist. ;)

DeddyH 6. Sep 2010 18:10

AW: TStringList ignoriert doppelte Einträge nicht
 
Mit IndexOf() geht das auch etwas kürzer (macht aber intern wohl genau dasselbe) ;)

zeras 6. Sep 2010 18:53

AW: TStringList ignoriert doppelte Einträge nicht
 
Zitat:

Zitat von DeddyH (Beitrag 1047867)
Mit IndexOf() geht das auch etwas kürzer (macht aber intern wohl genau dasselbe) ;)

.... und der Qulltext wird dafür bestimmt übersichtlicher. Ich nutze IndexOf() für solche Funktionen immer.

DeddyH 6. Sep 2010 18:58

AW: TStringList ignoriert doppelte Einträge nicht
 
Ich auch, ich wollte damit nur darauf hinweisen, dass man die angeregte Funktion gar nicht selbst schreiben muss, da ja bereits implementiert.

Matze 6. Sep 2010 19:04

AW: TStringList ignoriert doppelte Einträge nicht
 
Zitat:

Zitat von DeddyH (Beitrag 1047878)
Ich auch, ich wollte damit nur darauf hinweisen, dass man die angeregte Funktion gar nicht selbst schreiben muss, da ja bereits implementiert.

Jaja, ich hab einfach vergessen, dass es diese Funktion gibt. Ist gut jetzt. :mrgreen:
Ich würde IndexOf() natürlich auch der manuellen Implementierung vorziehen, keine Frage.

devidespe 6. Sep 2010 19:06

AW: TStringList ignoriert doppelte Einträge nicht
 
Vielen Dank für die Antworten. Ich habe IndexOf implementiert.

himitsu 6. Sep 2010 20:17

AW: TStringList ignoriert doppelte Einträge nicht
 
Auch wenn der Code, bei einer unsortierten Liste extrem langsam werden kann, was sich Aufgrund des Listentypes nicht ändern lößt.
Eine HashListe oder ein Suchindex in Form eines binären Baums oder einer weiteren Hashliste wäre besser.

Ich würde die OH ändern, vor den langsameren Einfügeoperationen waren und dann den Code so ändern:
Delphi-Quellcode:
procedure TStringList.Put(Index: Integer; const S: string);
begin
  if Cardinal(Index) >= Cardinal(FCount) then
    Error(@SListIndexError, Index);
  if (Duplicates <> dupIgnore) and (FList^[Index].FString <> S) and (IndexOf(S) >= 0) then
    case Duplicates of
      dupIgnore: begin
        Delete(Index);
        Exit;
      end;
      dupError: Error(@SDuplicateString, 0);
    end;
  Changing;
  FList^[Index].FString := S;
  Changed;
end;

function TStringList.AddObject(const S: string; AObject: TObject): Integer;
begin
  if not Sorted then
  begin
    if (Duplicates <> dupIgnore) and (IndexOf(S) >= 0) then
      case Duplicates of
        dupIgnore: Exit;
        dupError: Error(@SDuplicateString, 0);
      end;
    Result := FCount;
  end
  else
    if Find(S, Result) then
      case Duplicates of
        dupIgnore: Exit;
        dupError: Error(@SDuplicateString, 0);
      end;
  InsertItem(Result, S, AObject);
end;

procedure TStringList.InsertObject(Index: Integer; const S: string; AObject: TObject);
begin
  if Sorted then Error(@SSortedListError, 0);
  if (Index < 0) or (Index > FCount) then Error(@SListIndexError, Index);
  if (Duplicates <> dupIgnore) and (IndexOf(S) >= 0) then
    case Duplicates of
      dupIgnore: Exit;
      dupError: Error(@SDuplicateString, 0);
    end;
  InsertItem(Index, S, AObject);
end;
als neue Komponente ergibt das:
Delphi-Quellcode:
uses
  RTLConsts;

type
  TDupStringList = class(TStringList)
  protected
    procedure Put(Index: Integer; const S: string); override;
  public
    function AddObject(const S: String; AObject: TObject): Integer; override;
    procedure InsertObject(Index: Integer; const S: String; AObject: TObject); override;
  end;

procedure TDupStringList.Put(Index: Integer; const S: string);
begin
  if Cardinal(Index) >= Cardinal(Count) then
    Error(@SListIndexError, Index);
  if (Duplicates <> dupIgnore) and (Strings[Index] <> S) and (IndexOf(S) >= 0) then
    case Duplicates of
      dupIgnore: begin
        Delete(Index);
        Exit;
      end;
      dupError: Error(@SDuplicateString, 0);
    end;
  Inherited;
end;

function TDupStringList.AddObject(const S: string; AObject: TObject): Integer;
begin
  if not Sorted then
  begin
    if (Duplicates <> dupIgnore) and (IndexOf(S) >= 0) then
      case Duplicates of
        dupIgnore: Exit;
        dupError: Error(@SDuplicateString, 0);
      end;
    Result := Count;
  end
  else
    if Find(S, Result) then
      case Duplicates of
        dupIgnore: Exit;
        dupError: Error(@SDuplicateString, 0);
      end;
  InsertItem(Result, S, AObject);
end;

procedure TDupStringList.InsertObject(Index: Integer; const S: string; AObject: TObject);
begin
  if Sorted then Error(@SSortedListError, 0);
  if (Index < 0) or (Index > Count) then Error(@SListIndexError, Index);
  if (Duplicates <> dupIgnore) and (IndexOf(S) >= 0) then
    case Duplicates of
      dupIgnore: Exit;
      dupError: Error(@SDuplicateString, 0);
    end;
  InsertItem(Index, S, AObject);
end;
Code ungetestet, da einfach so dahingetippt, aber er sollte funktionieren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz