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 [Konzeptfrage] ist Listbox schneller zu durchsuchen? (https://www.delphipraxis.net/121266-%5Bkonzeptfrage%5D-ist-listbox-schneller-zu-durchsuchen.html)

juergen 24. Sep 2008 21:14


[Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Hallo zusammen,

ich durchsuche per for-Schleife eine Listbox..
Ich muss eine Scheife nehmen, weil ich per Enter immer weiter suchen lasse.
Suchtext eingeben -> Enter -> 1. Ergebnis
Enter -> 2. Ergebnis wird angezeigt usw.

Das funktioniert soweit, dauert allerdinngs bei ca. 8000 Einträgen auch schon bis zu 13 Sekunden... :cry:
Meine Kernkomponenten innerhalb der Schleife sind:
Delphi-Quellcode:
type
  TSuche = record
    Text: AnsiString;
    ItemPos: integer;
    StrPos: integer;
  end;
//...

var
  i, NextPos: Integer;
  ItemText: AnsiString;
begin
  if Suche.ItemPos = -1 then
    Suche.ItemPos := 0;
  Suche.Text := AnsiUpperCase(Edit1.Text); // Edit1 = Suchtext

  for i := Suche.ItemPos to Pred(Search_Form.Listbox.Count) do
  begin
    ItemText := AnsiUpperCase(Search_Form.Listbox.Items.Strings[i]);
    if Suche.StrPos > 0 then
    begin
      NextPos := pos(Suche.Text, Copy(ItemText, Suche.StrPos +
        length(Suche.Text), length(ItemText) - Suche.StrPos));
      if NextPos > 0 then
        Suche.StrPos := Suche.StrPos + length(Suche.Text) + NextPos - 1
      else
        Suche.StrPos := 0;
    end
    else
      Suche.StrPos := pos(Suche.Text, ItemText);
....
Ich hatte schon einiges optimiert (ursprünglich 21 Sek), bin nun aber zu obigen Ergebnis gelangt und habe damit das für mich Machbare erreicht.

Besteht hier überhaupt noch eine Chance das Ganze wesentlich zu beschleunigen?
Verbesserungen um einzelne Prozentpünktchen sind zwar generell auch interessant, aber so richtig interesant wäre alles was mehr wie 15% bringen würde.
Gibt es vllt. eine ganz andere Vorgehensweise?

Ich hatte schon die Idee alles in eine Textdatei zu speichern und diese dann zu durchsuchen.
Das würde sehr schnell gehen, aber wie suche ich dann jeweils weiter ohne eine Schleife?


Danke schon mal vorab!

grenzgaenger 24. Sep 2008 21:17

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
schon mal an .beginupdate und .endupdate gedacht :stupid:

DGL-luke 24. Sep 2008 21:28

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Und alles, was du aus GUI-Komponenten holst, zwischenspeichern! Das heißt in diesem Fall den Text des Edits und die Strings der Listbox. Zum Beginn der Suche in eine passend gescopete Variable kopieren und nur bei Änderung updaten.

juergen 24. Sep 2008 21:43

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Hallo,
Zitat:

Zitat von DGL-luke
Und alles, was du aus GUI-Komponenten holst, zwischenspeichern! Das heißt in diesem Fall den Text des Edits und die Strings der Listbox. Zum Beginn der Suche in eine passend gescopete Variable kopieren und nur bei Änderung updaten.

Da ich in der Listbox nichts ändere sondern nur einen String suche, bringt das doch nichts, oder?
Hab's auch gerade getestet, kein Unterschied.


Zitat:

Zitat von DGL-luke
Und alles, was du aus GUI-Komponenten holst, zwischenspeichern! Das heißt in diesem Fall den Text des Edits und die Strings der Listbox. Zum Beginn der Suche in eine passend gescopete Variable kopieren und nur bei Änderung updaten.

Den Text des Edits speichere ich schon zwischen:
Delphi-Quellcode:
Suche.Text := AnsiUpperCase(Edit1.Text);
"gescopete Variable kopieren und nur bei Änderung updaten" :gruebel: Verstehe ich nicht. Ich ändere doch nichts, ich informiere mich mal jetzt, was überhaupt eine gescopte Variable ist...

Schon mal Danke!

jfheins 24. Sep 2008 22:04

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Er meint, du sollst bereits vor der Suche die Listbox.Items in einer StringList zwischenspeichern, am besten bereits konvertiert.
Du suchst dann in der Stringlist ;)

Außerdem folgendes:
Delphi-Quellcode:
type
  TSuche = record
    Text: AnsiString;
    ItemPos: integer;
    StrPos: integer;
  end;
//...

var
  i, NextPos: Integer;
  ItemText: AnsiString;
begin
  if Suche.ItemPos = -1 then
    Suche.ItemPos := 0;
  Suche.Text := AnsiUpperCase(Edit1.Text); // Edit1 = Suchtext

  for i := Suche.ItemPos to Pred(Search_Form.Listbox.Count) do
  begin
    ItemText := AnsiUpperCase(Search_Form.Listbox.Items.Strings[i]);
    if Suche.StrPos > 0 then
    begin
      NextPos := pos(Suche.Text, Copy(ItemText, Suche.StrPos +
        length(Suche.Text), length(ItemText) - Suche.StrPos));
// vll. Nextpos = posex(Suche.Text im itemtext, nextpos + length(suche.text)) ???
// dann hier keine if abfrage, sondern einfach

      if NextPos > 0 then
        Suche.StrPos := NextPos; // siehe oben
      else
        Suche.StrPos := 0; // sinn? pos gibt doch nie werte < null zurück, oder?
    end
    else
      Suche.StrPos := pos(Suche.Text, ItemText);
....
;)

Luckie 24. Sep 2008 22:32

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Wie benutzerfreundlich ist denn eine Listbox mit 8000 Einträgen? :roll:

Hador 25. Sep 2008 04:10

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Zitat:

Zitat von juergen
Delphi-Quellcode:
[...]
      NextPos := pos(Suche.Text, Copy(ItemText, Suche.StrPos +
        length(Suche.Text), length(ItemText) - Suche.StrPos));
      if NextPos > 0 then
        Suche.StrPos := Suche.StrPos + length(Suche.Text) + NextPos - 1
      else
        Suche.StrPos := 0;
[...]

Da hast du aber zuerst einmal noch einen Fehler drin. Wenn der Suchtext "otto" ist und der durchsuchte Text "ottotto" enthält, so wird nur das erste Otto gefunden. Und um die Geschwindigkeit zu erhöhen könntest du den Copy-Befehl rausschmeißen und statt Delphi-Referenz durchsuchenPos mit Delphi-Referenz durchsuchenPosEx arbeiten:

Delphi-Quellcode:
[...]
      PosEx(Suche.Text, ItemText, Succ(Suche.StrPos));
      if NextPos > 0 then
        Suche.StrPos := Pred(NextPos) // Warum hier eigentlich einen weniger?
      else
        Suche.StrPos := 0;
[...]
Edit: Arrg, PosEx hatte jfheins ja schon genannt. Muss die Uhrzeit machen :wall:

alzaimar 25. Sep 2008 09:29

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
ListBox arbeitet intern mit einer Stringliste, es bringt also nichts, den Inhalt zu kopieren. Mit PosEx ist es sowieso viel schneller, denn der Bottleneck ist eindeutig die Verwendung von 'Copy'.

Ich habe den Code mal mit PosEx mit 20.000 Zeilen getestet (600k Text), Ohne Begin/EndUpdate, Suche direkt in der Listbox. Ergebnis: 200ms, um ein nicht existentes Wort in dem Text zu finden.

Dann habe ich den Text der Listbox vorher in einen String kopiert (fText := MyListBox.Items.Text). Das dauert 350ms. Dafür dauert das Suchen dann direkt in diesem String gemessene 0ms (also nicht meßbar).

Fazit: Wenn Du in einer sich nicht häufig ändernden Liste suchst, würde ich den Umweg über die Konvertierung in einen String gehen, sonst eben direkt in der Liste suchen (mit For-Schleife und PosEx).
Delphi-Quellcode:
procedure TForm1.btFindFirstClick(Sender: TObject);
begin
  fText := lb.items.text;
  fPos := 0;
  btSearchAgainClick(Sender);
end;


procedure TForm1.btFindAgainClick(Sender: TObject);
Var
  p,iLine,iCol : Integer;

  Procedure _CalcLineAndCol (aPos : Integer; Var aLine, aCol : Integer);
  Var
    i, iLineStart : Integer;

  Begin
    aLine := 1;
    For i:=1 to aPos do
      If Ftext[i]=#10 Then Begin
        iLineStart := i;
        inc(aLine);
        End;
    aCol := aPos - iLineStart;
  End;

begin
  p := csstrings.PosEx(edSearch.Text, fText,fPos+1);
  if p>0 Then Begin
    _CalcLineAndCol(p, iLine, iCol);
    lb.TopIndex := max(iLine-3, 1);
    fPos := p+Length (edSearch.Text)-1;
  End Else Raise Exception.Create('Suchstring nicht gefunden');
end;

DGL-luke 25. Sep 2008 14:17

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Scope ist der Gültigkeitsbereich einer Variable. Eine "entsprechend gescopete Variable" ist also eine, die den richtigen Gültigkeitsbereich hat, also für die ganze Suche gültig bleibt.

Der Sinn der Übung wäre, dafür zu sorgen, dass nicht bei jedem Suchvorgang auf eine Property zugegriffen werden muss. Aber alzaimar hat hier eine sicherlich ziemlich optimale Lösung gepostet.

jottkaerr 25. Sep 2008 15:35

Re: [Konzeptfrage] ist Listbox schneller zu durchsuchen?
 
Zitat:

Zitat von alzaimar
ListBox arbeitet intern mit einer Stringliste, es bringt also nichts, den Inhalt zu kopieren. Mit PosEx ist es sowieso viel schneller, denn der Bottleneck ist eindeutig die Verwendung von 'Copy'.

Hinter dem Items-Property von TListBox steckt ein TListBoxStrings-Objekt. Jeder Aufruf von dessen Get()- oder Put()-Methode löst einen Aufruf von SendMessage() aus. Dies mag zwar langsam sein, aber ein Umkopieren bringt in diesem Fall tatsächlich nichts, weil im Originalcode bereits immer nur einmal auf jedes Element zugegriffen wurde. Dieser eine Zugriff pro Element wäre auch beim Umkopieren in eine TStringList notwendig.

jkr


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