Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Duplikate in Stringlist (https://www.delphipraxis.net/153100-duplikate-stringlist.html)

youuu 20. Jul 2010 20:36

Duplikate in Stringlist
 
Hi, ich benutze diesen Algorithmus um Duplikate in einer Stringlist zu löschen, allerdings braucht dieser extrem lange bei 100.000 Einträgen und mehr.

Kennt jemand einen schnelleren?

Delphi-Quellcode:
procedure KillDuplicates(s: TStrings);
var
  iLow, iHigh: integer;
begin
  for iLow := 0 to s.Count - 1 do
    for iHigh := Pred(s.Count) downto Succ(iLow) do
      if s[iLow] = s[iHigh] then
        s.Delete(iHigh);
end;

Klaus01 20. Jul 2010 20:40

AW: Duplikate in Stringlist
 
Guten Abend,

darst Du die Liste sortieren, oder sollen
alle Einträge in der Reihenfolge beibehalten werden?

Grüße
Klaus

mkinzler 20. Jul 2010 20:42

AW: Duplikate in Stringlist
 
Besser wäre es das Einfügen von doppelten Einträgen zu verhindern.

youuu 20. Jul 2010 20:42

AW: Duplikate in Stringlist
 
Darfst Sortiert werden

Klaus01 20. Jul 2010 20:43

AW: Duplikate in Stringlist
 
Zitat:

Zitat von mkinzler (Beitrag 1036494)
Besser wäre es das Einfügen von doppelten Einträgen zu verhindern.

.. darauf wollte ich hinaus.

Zitat:

Class
TStringList

Syntax


Delphi-Quellcode:
 property Duplicates: TDuplicates read FDuplicates write FDuplicates;

Description
Set Duplicates to specify what should happen when an attempt is made to add a duplicate string to a sorted list. The CaseSensitive property controls whether two strings are considered duplicates if they are identical except for differences in case.

The value of Duplicates should be one of the following.
Value Meaning
dupIgnore
Ignore attempts to add duplicate strings to the list.

dupError
raise an EStringListError exception when an attempt is made to add duplicate strings to the sorted list.

dupAccept
Permit duplicate strings in the sorted list.


Set Duplicates before adding any strings to the list. Setting Duplicates to dupIgnore or dupError does nothing about duplicate strings that are already in the list.
Note:
Duplicates does nothing if the list is not sorted.

Grüße
Klaus

youuu 20. Jul 2010 20:44

AW: Duplikate in Stringlist
 
Wenn ich das mache Mkinzler, dann muss ich doch bei jeden Eintrag neu abfragen, ob dieser in der Liste existiert oder nicht, dann geht die Bearbeitungszeit ebenfalls nach oben, bei 100.000 und mehr Einträgen.

Oder versteh ich das falsch?

mkinzler 20. Jul 2010 20:45

AW: Duplikate in Stringlist
 
Ja, den eine Tlist hat diese Funktionalität schon (siehe Beitrag von Klaus)

youuu 20. Jul 2010 20:47

AW: Duplikate in Stringlist
 
Ah so?

StringList.Duplicates := dupError;
Und dann mit Except anfangen?

mkinzler 20. Jul 2010 20:48

AW: Duplikate in Stringlist
 
dupIgnore wäre besser

Matze 20. Jul 2010 20:48

AW: Duplikate in Stringlist
 
Ich glaube, das geht nur in Verbindung mit "Sorted" oder?

Das funktioniert:
Delphi-Quellcode:
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    sl.Duplicates := dupIgnore;
    sl.Sorted := true;

    sl.Add('a');
    sl.Add('b');
    sl.Add('a');

    ShowMessage(sl.Text);
  finally
    FreeAndNil(sl);
  end;
end;
Ohne "Sorted := true;" geht es nicht.

Nachtrag: Ah, das steht in Klaus' Zitat am Ende, sehe ich gerade "Duplicates does nothing if the list is not sorted." :wall:

youuu 20. Jul 2010 20:50

AW: Duplikate in Stringlist
 
Super danke

mkinzler 20. Jul 2010 20:51

AW: Duplikate in Stringlist
 
Ja, das steht aber auch schon in Klaus' Beitrag
Alternativ könnte man mit .IndexOf() auf Vorhandensein prüfen; ist aber langsamer funktioniert aber auch unsortiert

fatalerror 20. Jul 2010 21:16

AW: Duplikate in Stringlist
 
Wenn in einer Liste aber bereits vorhandene Duplikate stehen (so wie im ursprünglichen Posting angegeben) würde ich die Liste kopieren, dies sollte bedeutend schneller gehen als das Prüfen mit deiner Routine:

Nur so hingetippt ohne zu überprüfen obs auch funktioniert

Delphi-Quellcode:
var
sl1, sl2:TSTringlist;
i:Integer;
t_start, t_stop:integer;

iLow, iHigh: integer;

begin
sl1:= Tstringlist.Create;
sl2:=TStringlist.Create;

try
  sl1.loadfromFile('c:\temp\testfîle.lst'); //laden einer Stringliste

  //Variante mit neuer Stringliste
  sl2.Duplicates:= dupignore;
  sl2.Sorted:=true;

  t_start := gettickcount;
  sl2.Assign(Sl1); //Einträge der zweiten Stringliste zuordnen
  t_stop := gettickcount;
  showmessage('Variante1; ' +inttostr(t_stop - t_start)+  ' ms');

  //Variante2 kopiert aus dem Originalposting

  t_start := gettickcount;
  for iLow := 0 to sl1.Count - 2 do
    for iHigh := Pred(sl1.Count) downto Succ(iLow) do
      if sl1[iLow] = sl1[iHigh] then
        sl1.Delete(iHigh);

  t_stop := gettickcount;
  showmessage('Variante2: ' +inttostr(t_stop - t_start)+  ' ms');

finally
 sl1.Free;
 sl2.Free;

end;

alzaimar 20. Jul 2010 21:36

AW: Duplikate in Stringlist
 
Eine Hashmap prüft das Vorhandensein eines Strings wesentlich effektiver, als das in der TStringList eingebaute 'Duplicates'. Beim Einfügen dürfte das die bei weitem schnellste Möglichkeit sein.

Du kannst Dir auch die THashedStringList aus der Unit 'IniFiles' nehmen, die hier vielleicht auch schnell genug sein könnte.

youuu 21. Jul 2010 10:09

AW: Duplikate in Stringlist
 
Habe noch eine Frage.

Ich hab nun 2 Stringlisten.

1. Duplikate die nicht in die neue Strinlit aufgenommen werden soll
und
2. die neue Stringlist.

Delphi-Quellcode:
        Try
          sOld.Duplicates := dupError;
          sOld.Sorted := true;

          sOld.Add(url); // Abgleich Stringlist
          s.Add(url); // Neu Link Stringlist
        except
          on EStringListError do    

        end;
Habe also "sOld" = Duplikate die nicht in die neue Stringlist "s" aufgenommen werden sollen.
Allerdings funktioniert das auch, jedoch statt 2 Sekunden, normaler ab Arbeitungszeit, der Procedure nun 9-15 Sekunden, nur durch diesen Codeteil.

mkinzler 21. Jul 2010 10:57

AW: Duplikate in Stringlist
 
Wie gesagt ist es besser dupIgnore zu setzen. Denn so wird ja bei jedem doppelten Vorkommen eine Exception ausgelöst!
dupError benötigst du nur, wenn du auf dies in irgendeiner Form reagieren willst.

Btw.: das mit dem Delphi-Tag statt Code-Tag gilt für alle Beiträge

youuu 21. Jul 2010 11:11

AW: Duplikate in Stringlist
 
Das Problem bei Dupignor ist allerdings nun das ich in der Stinglist "s" keine Einträge aus der Stringlist sOld haben möchte, sowie die duplikate aus der sOld.

Daher hab ich dies mit einer Exception versucht zulösen, da dann ja "s.add()" übersprungen wird sobald in sOld ein Duplikat eingetragen werden sollte.

mkinzler 21. Jul 2010 11:15

AW: Duplikate in Stringlist
 
Rate mal was dupIgnore macht? Oder schau in der Hilfe nach.

youuu 21. Jul 2010 11:20

AW: Duplikate in Stringlist
 
Ich weiß schon was dupignore macht, aber ich habe 2 Stringlisten.

Eine mit duplikaten und eine leere und in der leeren sollen auch keine duplicate aus der 1. eingeführt werden.

Das heißt ich muss ja testen ob ein duplikate in der 1. eingefügt werden sollte, wenn ja füge es nicht in die 2. Liste ein.

Nur weiß ich nicht wie ich das anders als über die exception in Erfahrung bringe.

mkinzler 21. Jul 2010 11:30

AW: Duplikate in Stringlist
 
Delphi-Quellcode:
          if sOld.IndexOf( url) = -1 then
              s.Add(url); // Neu Link Stringlist

youuu 21. Jul 2010 11:39

AW: Duplikate in Stringlist
 
Super funktioniert, kostet allerdings immernoch etwas Performance statt 9-15 Sekunden, sind es nun 3 Sekunden von damals 2 - 2,6 Sekunden.

Schneller wird es nicht möglich sein oder?

mkinzler 21. Jul 2010 11:42

AW: Duplikate in Stringlist
 
Möglicherweise mit einer THashedStringList

youuu 21. Jul 2010 12:07

AW: Duplikate in Stringlist
 
Ok gerade mit größeren Datensätzen probiert mit IndexOf und bei sovielen Datensätzen wie ich in der Liste haber, dauert das 20-40 Sekunden.

Das ist einfach nicht tragbar.

Bernhard Geyer 21. Jul 2010 12:21

AW: Duplikate in Stringlist
 
Zitat:

Zitat von youuu (Beitrag 1036580)
Schneller wird es nicht möglich sein oder?

Doch. HashTree/BTree sind bei großen Datenmengen um Welten schneller.

youuu 21. Jul 2010 12:51

AW: Duplikate in Stringlist
 
Soeben mit THashedStringList probiert und das gab wirklich einen extremen Performance boost.

xZise 21. Jul 2010 14:12

AW: Duplikate in Stringlist
 
Moin,
Zitat:

Zitat von youuu (Beitrag 1036602)
Soeben mit THashedStringList probiert und das gab wirklich einen extremen Performance boost.

Weil es ein anderes Verfahren ist. In einer Liste mit 100.000 Einträgen, weißt du ja nicht sofort ob ein Eintrag bereits vorhanden ist, sondern musst im schlimmsten Fall alle Einträge überprüfen.

Eine HashedStringList (wenn das sowas ähnliches ist wie eine Hashmap ist), hingegen definiert, wo ein Wert steht, anhand des Inhalts (z.B.). Also wenn du den Text Foo hast, dann weiß er wo das so ungefähr ist.

MfG
Fabian

Sandi007 14. Jun 2015 10:51

AW: Duplikate in Stringlist
 
Zitat:

Zitat von Matze (Beitrag 1036501)
...
Delphi-Quellcode:
var
    sl.Add('a');
Ohne "Sorted := true;" geht es nicht.
...

ja, und auch nur mit .Add, mit .Append geht es auch nicht.

Dejan Vu 14. Jun 2015 16:43

AW: Duplikate in Stringlist
 
Zitat:

Zitat von alzaimar (Beitrag 1036509)
Eine Hashmap prüft das Vorhandensein eines Strings wesentlich effektiver, als das in der TStringList eingebaute 'Duplicates'. Beim Einfügen dürfte das die bei weitem schnellste Möglichkeit sein.

Du kannst Dir auch die THashedStringList aus der Unit 'IniFiles' nehmen, die hier vielleicht auch schnell genug sein könnte.

Lustig. Auch 5 Jahre alte Tipps sind immer noch gültig.

EDIT: Unnötige Bemerkung entfernt.


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