Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Dubikate in TStringGrid anzeigen (den Rest rausschmeißen)... (https://www.delphipraxis.net/51524-dubikate-tstringgrid-anzeigen-den-rest-rausschmeissen.html)

yankee 14. Aug 2005 08:30


Dubikate in TStringGrid anzeigen (den Rest rausschmeißen)...
 
Ich glaube ich habe da mal eine kleine Denkblokade oder so. Normalerweise ist es ja so, dass man versucht Dublikate zu entfernen. Aber bei mir ist es andersrum, denn die Einträge, die nicht doppelt sind, sind in Ordung und die will ich aus dem StringGrid schmeißen. Genauer gesagt geht es nur um eine Spalte des StringGrids, die nur Integerwerte enthält und sortiert ist.

Es ist wahsrcheinlich total banal udn ich komme einfach nicht drauf :wall: . Also, wäre nett, wenn mir einer helfen würde *Hundeblick*

Keldorn 14. Aug 2005 09:10

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Hallo

Du kannst dir die Cols-eigenschaft vom Grid zu Hilfe nehmen, sind auch tstrings. Durchlauf sie vom ende und prüf mit indexof, ob der Wert nochmal in der Spalte enthalten ist. Wenn indexof dir die aktuelle Position zurückgibt, ist der Eintrag nicht doppelt drin. Liefert indexof einen kleineren Wert, steht der gleiche Eintrag schon mal vorher in der Liste, dann löschen und nochmal suchen.

Mfg Frank

Sharky 14. Aug 2005 09:17

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Hai yankee,

hier noch eine alternative Methode (zum testen habe ich eine ListBox genommen):
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ndx: integer;
begin
  with ListBox1 do
  begin
    for ndx := Count - 2 downto 1 do
    begin
      if not ((Items[ndx] = Items[ndx + 1]) or (Items[ndx] = Items[ndx - 1])) then
      begin
        Items.Delete(ndx);
      end;
    end;
  // Schleifen ende
    if not (Items[0] = Items[1]) then // erster <> zweiter
    begin
      Items.Delete(0);
    end;
    if not (Items[Count-1] = Items[Count-2]) then // letzer <> vorletzer
    begin
      Items.Delete(Count-1);
    end;
  end;
end;
Ich durchlaufe von unten nach oben die Einträge von count -2 (vorletzter) bis 1 (zweiter) und prüfe ob der Eintrag davor oder danach gleich dem aktuellen ist. Wenn dies nicht zutrifft lösche ich den aktuellen.
Ganz zum schluss prüfe ich noch ob der erste = dem zweiten ist bzw. der letze = dem vorletzten.

Aber die Methode von Keldorn ist auch sehr elegant :stupid:

marabu 14. Aug 2005 09:55

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Die von Frank beschriebene Methode kenne ich aus meiner code library:

Delphi-Quellcode:
procedure KeepDuplicates(sl: TStringList; allDuplicates: boolean = false);
var
  i, dist: integer;
begin
  if not sl.Sorted then
    sl.Sort;
  for i := sl.Count - 1 downto 0 do begin
    dist := i - sl.IndexOf(sl[i]);
    if dist > i then Continue;
    if (dist = 0) or (not allDuplicates and (dist > 1)) then
      sl.Delete(i);
  end;
end;
Grüße vom marabu

Sharky 14. Aug 2005 10:18

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hai marabu,

kann es sein das dein Code einen Fehler hat? Wenn ich diesen mit meiner Listbox verwende (vorher alles in eine SL kopier).
stimmt das Ergebniss nicht mit der Aufgabe überein. :gruebel:

Ich hänge mein Testprojekt mal an.

alzaimar 14. Aug 2005 10:43

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Kann ich mich bei einem TStringList.IndexOf denn darauf verlassen, das bei doppeltem Vorkommen immer der erste Eintrag gefunden wird, vor allen Dingen, wenn die TStringList.sorted = True ist? Ich weiss, eine ketzterische Frage.

Um auf Nummer Sicher zu gehen, würde ich mir die Mühe machen, das IndexOf durch eine kleine eigene Routine ersetzt, die prüft, ob ein Wert in der Unterliste (0..n) vorhanden ist, oder nicht.

Bei einer sortierten Liste (wie in deiner Codelibrary) liegen Duplikate naturgemäß nebeneinander, insofern erübrigt sich eine Suche mit IndexOf: Entweder ist mein Vorgänger mit mir identisch, oder eben nicht. Desweiteren sollten Duplikate nur 1x auftreten.
Hier also mein Versuch (er erstellt aber eine zweite Liste, die die doppelten Einträge enthält):
Delphi-Quellcode:
Procedure FindDuplicates (aList, aDuplicates : TStringList);
Var
  i : Integer;
  sSample : String;

Begin
  aList.Sort;
  i := 1;
  sSample := aList [0];
  While i<aList.Count - 1 do begin
    j := i;
    While aList[i] = sSample do
      inc (i);
    if j< i - 1 then
      aDuplicates.add(sSample);
    sSample := aList[i];
    End;
End;

Keldorn 14. Aug 2005 10:52

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Zitat:

Zitat von alzaimar
Kann ich mich bei einem TStringList.IndexOf denn darauf verlassen, das bei doppeltem Vorkommen immer der erste Eintrag gefunden wird, vor allen Dingen, wenn die TStringList.sorted = True ist?

Ich weiß jetz nicht genau, auf was du anspielst, aber deswegen fängt man von hinten an und prüft, ob der Eintrag schon mal weiter vorn in der Liste ist.

Das mit dem sortieren geht sicher auch, aber es ist nicht unbedingt immer gewünscht, das nach dem Löschen der doppelten Einträge die Liste auch noch sortiert ist und die ursprüngliche Reihenfolge verloren ist.

marabu 14. Aug 2005 11:27

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Sharky, du hast tatsächlich einen Fehler in meiner Routine gefunden und alzaimar hat ihn korrekt erklärt. Vielen Dank euch beiden.

Delphi-Quellcode:
procedure KeepDuplicates(sl: TStringList; allDuplicates: boolean = false);
var
  i, j, dist: integer;
begin
  if not sl.Sorted then
    sl.Sort;
  for i := sl.Count - 1 downto 0 do begin
    j := i; // "j := sl.IndexOf(sl[i])" würde einen sporadischen Fehler produzieren
    while (j > 0) and (sl[j - 1] = sl[j]) do
      Dec(j);
    dist := i - j;
    if (dist = 0) or (not allDuplicates and (dist > 1)) then
      sl.Delete(i);
  end;
end;
Die Routine stammt aus einer Sammlung von Mengenoperationen auf Strings. Benutzt habe ich sie nie, aber der zugehörige Testcode erzeugte seine Testdaten so:

Delphi-Quellcode:
for i := 1 to 20 do
  sl.Add(IntToStr(Random(30)));
Was soll ich sagen, damit produzierte der Code in den ersten Durchläufen korrekte Ergebnisse. Ich werde meinen Testcode wohl etwas verfeinern müssen...

Verlegene Grüße vom marabu

PS: Fehler nach Hinweis von alzaimar korrigiert

alzaimar 14. Aug 2005 11:28

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Wenn Du bei einer TStringList Sorted auf True setzt, dann wird beim IndexOf nicht sequentiell, sondern binär gesucht (binarysearch). Das findet aber nur irgendeinen Eintrag, aber nicht unbedingt den Ersten. Beispiel: Liste = (1,2,2,2,3). Suche nach 2 liefert im ersten Durchgang einen Treffer, nämlich l[2] ='2', das ist aber nicht das erste Auftreten. Deshalb ist die Verwendung des Suchergebnisses als Kriterium für doppelte Einträge bei sortierten Stringlisten (Sorted = True) nur bedingt anwendbar. Im Beispiel vom marabu umgeht er das, indem er von hinten an die Sache rangeht.

Noch eine Anmerkung zum marabu-Verfahren: Man kann die Zeile
Delphi-Quellcode:
j := sl.IndexOf (sl[i]);
durch
Delphi-Quellcode:
j := i;
ersetzen, da die Liste sortiert ist und j danach sowieso auf das erste Element gesetzt wird.

marabu 14. Aug 2005 13:32

Re: Dubikate in TStringGrid anzeigen (den Rest rausschmeißen
 
Hallo alzaimar,

man KANN nicht nur IndexOf() durch die Gleichsetzung von j mit i ersetzen, man MUSS es sogar. Habe ich auch so in meiner library geändert und doch den falschen Code hier bereit gestellt. Muss unbedingt ein Seminar zum Thema Copy & Paste besuchen...

Nochmal danke
marabu


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:45 Uhr.
Seite 1 von 2  1 2      

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