Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Prozedur zu langsam, Optimierung nötig (https://www.delphipraxis.net/88009-prozedur-zu-langsam-optimierung-noetig.html)

carknue 8. Mär 2007 20:44


Prozedur zu langsam, Optimierung nötig
 
Hallo,

ich habe eine kleine Prozedur geschrieben, die aus einer GPS Text Datei für jede Koordinate den besten Messwert raussuchen soll und diesen in eine neue Datei schreiben soll. Meine angehängte Prozedur macht das auch ganz gut. Das Problem ist nur, dass diese Messdateien sehr groß sind, ca 100.000 Zeilen bei 4 Mb Größe. Mit solch großen Dateien dauert diese Prozedur mehrere Stunden auf durchaus aktueller Hardware. Meine Frage ist jetzt, wie könnte man diese Prozedur optimieren. Gleiche Koordinaten kommen in dieser Datei öfters vor, optimal wäre es, wenn im neuen File jede Koordinate wirklich nur 1 Mal stehen würde, mit natürlich dem besten Wert. Mit meiner Prozedur steht da diese Koordinate genau so oft, wie vorher drin aber wenigstens immer mit dem besten Wert. Hat jemand vielleicht ein e Idee?


Delphi-Quellcode:
procedure TForm1.Button4Click(Sender: TObject);
var
  f,g,h: Textfile;
  zeile,rxl: string;
  suchkoor: string;
  Zeileg: string;
  Koor: Array[0..1000] of string;
  i,l,maxi: Integer;
  maxrxl: Integer;


begin
 Screen.Cursor:=crHourglass;
 DecimalSeparator:='.';
 AssignFile(f,OpenDialog1.FileName);
 Reset(f);
 readln(f,Zeile);
 AssignFile(g,OpenDialog1.FileName);
 Reset(g);
 readln(g,Zeileg);
 AssignFile(h,'C:\Best_Server.txt');
 rewrite(h);
 Writeln(h,'lon'+chr(9)+'lat'+chr(9)+'RXL'+chr(9)+'CID'+chr(9)+'BCCH');
 repeat
   readln(f,Zeile);
   suchkoor:=copy(Zeile,1,GetPosNumX(chr(9),Zeile,2)-1);
   reset(g);
   readln(g,Zeileg);
   i:=0;
   repeat
     readln(g,Zeileg);
     if pos(suchkoor,Zeileg)>0 then
     begin
       koor[i]:=Zeileg;
       i:=i+1;
     end;

   until EOF(g);
   maxrxl:=-200;
   maxi:=0;
   if i=1 then Writeln(h,koor[0])
   else
   begin
     for l := 0 to i - 1 do
     begin
       rxl:=copy(koor[l],GetPosNumX(chr(9),koor[l],2)+1,GetPosNumX(chr(9),koor[l],3)-GetPosNumX(chr(9),koor[l],2)-1);
       label11.Caption:=koor[l];
       label12.Caption:=inttostr(i);
       update;
       if strtoint(rxl)>maxrxl then
       begin
        maxrxl:=strtoint(rxl);
        maxi:=l;
       end;
     end;
     Writeln(h,koor[maxi]);

   end;

 until EOF(f);
 closefile(f);
 closefile(g);
 closefile(h);
 Screen.Cursor:=crDefault;
end;

DP-Maintenance 8. Mär 2007 20:48

DP-Maintenance
 
Dieses Thema wurde von "SirThornberry" von "Sonstige Fragen zu Delphi" nach "Object-Pascal / Delphi-Language" verschoben.

SirThornberry 8. Mär 2007 20:48

Re: Prozedur zu langsam, Optimierung nötig
 
wenn wir etwas optimieren sollen musst du uns auch alles geben was optimierbar ist (auch GetPosNumX)

Thanatos81 8. Mär 2007 21:52

Re: Prozedur zu langsam, Optimierung nötig
 
Wenn ich das richtig sehe, werden f und g die selbe Datei zugewiesen, dann durchläufst du f von Anfang bis Ende und in jedem Durchlauf(f) durchläufst du g komplett.

Bei jedem Durchlauf(f) wird g erneut geöffnet. Und jedes readLn liest von der Platte. Das kostet natürlich unheimlich Zeit.

Ich würde statt dessen folgender Herangehensweise versuchen.
  • Datei öffnen
  • Daten in ein passendes Record schreiben
  • Record per Hier im Forum suchenQuicksort nach Koordinaten sortieren
  • Eine Variable "letzteKoords" und ein Array "besterWert/Koord" einführen
  • Record durchlaufen und prüfen ob letzteKoords = aktuelle Koords, falls ja, schauen ob aktueller Wert besser, dann im Array speichern
  • Zum Schluss alles in eine neue Datei speichern.

GetPosNumX wäre aber wirklich hilfreich.

carknue 8. Mär 2007 21:57

Re: Prozedur zu langsam, Optimierung nötig
 
Ok, sorry aber ich dachte GetPosNumX wäre hier bekannt, da es von hier kommt.

Noch zur Erklärung, jede Zeile ist ein Messwert. Zuerst die x und y Koordinate, und dann der rxl Messwert. Alles mit Tabs chr(9) getrennt.

IngoD7 8. Mär 2007 22:01

Re: Prozedur zu langsam, Optimierung nötig
 
Zitat:

Zitat von SirThornberry
wenn wir etwas optimieren sollen musst du uns auch alles geben was optimierbar ist (auch GetPosNumX)

Zitat:

Zitat von carknue
Ok, sorry aber ich dachte GetPosNumX wäre hier bekannt, da es von hier kommt.

:mrgreen: :mrgreen:
So, SirThornberry, nun mach deinen eigenen Code auch mal etwas schneller bitte. :wink:

SirThornberry 8. Mär 2007 22:22

Re: Prozedur zu langsam, Optimierung nötig
 
uj, das ist schon so lange her :oops: Aber wie bereits erwähnt sollte das langsamste sein das hier mit dateien gearbeitet wird. Das schnellste wäre wenn du die Datei in einem rutsch in den Arbeitsspeicher liest (und nicht in vielen kleinen stücken immer wieder liest) und dann kannst du mit der Datei im Arbeitsspeicher um ein vielfaches schneller arbeiten.

Hawkeye219 8. Mär 2007 23:04

Re: Prozedur zu langsam, Optimierung nötig
 
Hallo,

interessant wären noch die Art der Werte (integer, real) und der Wertebereich (falls möglich). Vielleicht kannst du auch ein paar Beispielzeilen aus der Eingabedatei zeigen.

Gruß Hawkeye

carknue 8. Mär 2007 23:23

Re: Prozedur zu langsam, Optimierung nötig
 
Klar, hier ein Beispiel, die erste Zeile ist die Überschrift, die in jeder Datei enthalten ist.

lon lat RXL CID BCCH
6.612051 51.329779 -70 00276 963
6.6122 51.3297 -67 00276 963
6.612051 51.329779 -61 00275 973


Wie gesagt, die Werte sind mit Tabs getrennt. rxl sind immer negative integer von -120 bis -40. lon und lat sind Fließkommazahlen mit unterschiedlich Nachkommastellen.

Den Vorschlag mit Nach Koordinate sortieren, habe ich noch nicht ganz verstanden. Eine Koordinate besteht doch aus zwei Werten, lon und lat. Nach welchem soll ich dann sortieren?

Und wichtig wäre, dass keine doppelten Koordinaten mehr in der Ausgangs Datei sind, sondern nur einmal mit dem größten Wert von rxl

Gruß
Carsten

Hawkeye219 9. Mär 2007 00:28

Re: Prozedur zu langsam, Optimierung nötig
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, im Anhang findest du einen Vorschlag zur Lösung deines Problems mit Hilfe einer sparse matrix. Die Koordinaten dienen dabei als Index, jedes Matrixelement speichert den RXL-Wert und den Zeilenrest. Ich habe einige wenige Stellen kommentiert, der Rest ist (hoffentlich) selbsterklärend. Die Unit gewinnt sicher keinen Schönheitspreis und ist möglicherweise auch nicht fehlerfrei. Betrachte sie einfach als Anregung.

Gruß Hawkeye

oldmax 9. Mär 2007 06:20

Re: Prozedur zu langsam, Optimierung nötig
 
Hi
Nun, ich denke, die Ablage der Daten in eine Datenbank und die Suchen durch SQL-Anweisung bringen erhebliche Geschwindigkeitsvorteile. Auch wenn's sich kompliziert anhört, ich würd's damit lösen. Filezugriffe sind nun mal einfach zu langsam.
Gruß oldmax

Reinhard Kern 9. Mär 2007 13:07

Re: Prozedur zu langsam, Optimierung nötig
 
Zitat:

Zitat von carknue
Klar, hier ein Beispiel, die erste Zeile ist die Überschrift, die in jeder Datei enthalten ist.

lon lat RXL CID BCCH
6.612051 51.329779 -70 00276 963
6.6122 51.3297 -67 00276 963
6.612051 51.329779 -61 00275 973


Wie gesagt, die Werte sind mit Tabs getrennt. rxl sind immer negative integer von -120 bis -40. lon und lat sind Fließkommazahlen mit unterschiedlich Nachkommastellen.

Den Vorschlag mit Nach Koordinate sortieren, habe ich noch nicht ganz verstanden. Eine Koordinate besteht doch aus zwei Werten, lon und lat. Nach welchem soll ich dann sortieren?

Und wichtig wäre, dass keine doppelten Koordinaten mehr in der Ausgangs Datei sind, sondern nur einmal mit dem größten Wert von rxl

Gruß
Carsten

Sortiert wird erst nach lon, dann nach lat: zum Sortieren must du ja eine Vergleichsfunktion liefern, die vergleicht also lon1 und lon2, nur wenn die gleich sind, vergleicht sie lat1 und lat2. Da das selten vorkommt, hat das nicht mal grossen Einfluss auf die Rechenzeit.

Eine andere Möglichkeit: du liest alles gleich sortiert ein, d.h. jeder Record wird gleich am richtigen Platz eingefügt (mit binärer Suche). Steht da schon einer mit den gleichen Koordinaten, so brauchst du nur den mit dem besseren Wert zu speichern. Dann ist nach dem Einlesen auch schon alles so gut wie fertig. Das gibt natürlich eine Menge Schieberei, aber die braucht jedes Sortierprogramm.

Gruss Reinhard

carknue 11. Mär 2007 15:43

Re: Prozedur zu langsam, Optimierung nötig
 
Ich habe jetzt mal den Tip, die Festplatten Zugriffe durch Open, Close und read und writeln möglichst wegzulassen befolgt. Dies hat in einer anderen Prozedur in meinem Programm auch einen erhelblichen Geschwindigkeitszuwachs gebracht. Mit Matritzen, Quickseach usw. blick ich leider nicht durch, deswegen habe ich die Prozedur jetzt mal so geändert. Leider ist diese Variante überhaupt nicht schneller, würde eher sagen deutlich langsamer. Wo ist denn da jetzt der Flaschenhals? Das Loadfrom File geht noch recht schnell aber dann braucht der Rechner bestimmt 1-5 Sekunden pro Zeile. Die Listboxen habe ich unsichtbar gemacht.

Delphi-Quellcode:
procedure TForm1.Button7Click(Sender: TObject);
var
  rxl: string;
  suchkoor: string;
  Koor: Array[0..1000] of string;
  i,l,k,j,maxi: Integer;
  maxrxl: Integer;


begin
 Screen.Cursor:=crHourglass;
 DecimalSeparator:='.';
 listbox1.Clear;
 listbox2.Clear;
 listbox2.items.Add('lon'+chr(9)+'lat'+chr(9)+'RXL'+chr(9)+'CID'+chr(9)+'BCCH');
 listbox1.Items.LoadFromFile(OpenDialog1.FileName);
 label10.Caption:=inttostr(listbox1.Items.Count);
 update;
 i:=1;
 repeat
     suchkoor:=copy(Listbox1.Items[i],1,GetPosNumX(chr(9),Listbox1.Items[i],2)-1);
     l:=1;
     k:=0;
     repeat
       if pos(suchkoor,listbox1.Items[l])>0 then
       begin
        koor[k]:=listbox1.Items[l];
        k:=k+1;
        listbox1.Items.Delete(l);
        l:=l-1;
       end;
       l:=l+1;
     until l=listbox1.Items.Count-1;
     maxrxl:=-200;
     maxi:=0;
   if k=1 then listbox2.Items.Add(koor[0])
   else
   begin
     for j := 0 to k - 1 do
     begin
       rxl:=copy(koor[j],GetPosNumX(chr(9),koor[j],2)+1,GetPosNumX(chr(9),koor[j],3)-GetPosNumX(chr(9),koor[j],2)-1);
       label11.Caption:=koor[j];
       label12.Caption:=inttostr(k);
       update;
       if strtoint(rxl)>maxrxl then
       begin
        maxrxl:=strtoint(rxl);
        maxi:=j;
       end;
     end;
     listbox2.Items.Add(koor[maxi]);

   end;
    i:=1;
   until i=listbox1.Items.count-1 ;

 listbox2.Items.SaveToFile('c:\bs.txt');
 Screen.Cursor:=crDefault;
end;
Gruß
Carsten

Ghostwalker 12. Mär 2007 07:36

Re: Prozedur zu langsam, Optimierung nötig
 
Also spontan:

1. Statt einer Listbox eine Stringliste verwenden
2. BeginUpdate/EndUpdate vor/nach der Verarbeitung
3. Um die Copy's zu sparen, die Eigenschaft Delimiter auf TAB setzen. Damit dröselt die Stringliste
die Werte in einzelne Zeilen auf und du kannst dir die copy's und Pos sparen. Jeweils 5 Zeilen in
der Stringlist würden dann einer Zeile in der Datei entsprechen.

Mavarik 12. Mär 2007 09:45

Re: Prozedur zu langsam, Optimierung nötig
 
Zitat:

Zitat von carknue
lon lat RXL CID BCCH
6.612051 51.329779 -70 00276 963
6.6122 51.3297 -67 00276 963
6.612051 51.329779 -61 00275 973

OK wie wäre es mit diesem Ansatz:

Bilde aus lon und lat einen CRC32
Erzeuge Dir einen Record im Speicher für die o.g. Daten
Erzeuge eine sortierte Liste von der CRC32 koordinaten mit einem Pointer auf den entsprechenden Record...
Oder noch schneller immer 1000 Datensätze einlesen, dann die Liste wieder per Qsort sortieren und doppelte löschen...

Würde sagen dauert dann noch 10-15 sekunde um alles zu erzeugen...

Frank :coder:

PS:Ich bin Pilot und habe mit GPS öffter zu tun, daher die Frage... Was sind das für Daten und woher kommen die bzw. was machst Du damit?

Michael Habbe 12. Mär 2007 13:28

Re: Prozedur zu langsam, Optimierung nötig
 
Hi,

versuche doch einfach erstmal die Daten aus der Textdatei in eine Datenbank einzulesen, z. B. JvMemoryData von den JediVCL.

Hier mal mein Beispiel des Einlesens einer vorher gespeicherten Inventur:
Delphi-Quellcode:
procedure blablupp;
var
  F: TextFile;
  zeile: string;
  art, men, bez, ek, lag: string;
  errorcount: integer;
  k  : array [1..6] of Integer;
  Posi: integer;
  lauf: integer;
  dat : string;
begin
  AssignFile(F, FileName);
  Reset(F);

  MemTbl.EmptyTable;
  while not eof(f) do
  begin
    ReadLn(f, Zeile);
    try
      // Bestimmung der Trennzeichenpositionen
      Posi:=1;
      for Lauf := 1 to length(Zeile) do
      begin
        if (Zeile[Lauf] = #9) then
        begin
          K[Posi] := Lauf;
          Inc(Posi);
        end;
      end;
      K[6] := Length(Zeile)+1;

      art := copy(Zeile, 1, K[1]-1);
      men := copy(Zeile, K[1]+1, K[2]-K[1]-1);
      bez := copy(Zeile, K[2]+1, K[3]-K[2]-1);
      ek := copy(Zeile, K[3]+1, K[4]-K[3]-1);
      dat := copy(Zeile, K[4]+1, K[5]-K[4]-1);
      lag := copy(Zeile, K[5]+1, K[6]-K[5]-1);
      MemTbl.Append;
      MemTblArtikelnummer.AsString := art;
      MemTblBezeichnung1.AsString := bez;
      MemTblEinkaufspreis.AsString := ek;
      MemTblMenge.AsString := men;
      MemTblZaehldatum.AsString := dat;
      MemTblLagerort.AsString := lag;
      MemTbl.Post;
    except
      inc(errorcount);
      MemTbl.Cancel;
    end;
  end;
  CloseFile(f);
end;
Wenn Du anschließend die Daten in der Tabelle hast, kannst Du mit TDataSet-Funktionen Deine Auswertung weiterlaufen lassen.

So wird die Datei jedenfalls nur ein einziges Mal angerührt.

mfg
Michael

carknue 17. Mär 2007 14:40

Re: Prozedur zu langsam, Optimierung nötig
 
Ich denke, ich habe jetzt eine brauchbare Lösung gefunden. Nach der Stringbox Variante hatte ich es noch mit variablen Arrays versucht. Dies war dann schon deutlich schneller. Von ursprünglich über 3 Stunden für 120.000 Zeilen auf ca 20 Minuten auf einem E6600. Auf einem Celeron D war es dann mit gut einer Stunde immer noch unzumutbar. Habe es dann mit Stringlisten und einem kleinen Array probiert. Hierbei wird jeder gefundene Eintrag sofort gelöscht, damit wird die Routine immer schneller. Nun braucht die Prozedur nur noch 2.5 Minuten auf dem E6600. Und der Code wird auch immer kleiner :wink: Das Sortieren würde bei 120.000 Zeilen ja auch etwas dauern und wenn ich jeden Wert in eine Zeile schreiben würde, hätte ich 600.000 Zeilen. Müßte ich vielleicht nochmal ausprobieren, was das noch bringt.

Hier mein Code:

Delphi-Quellcode:
procedure TForm1.Button8Click(Sender: TObject);
var
  rxl: string;
  suchkoor: string;
  Koor: Array[0..1000] of string[35];
  i,l,k,j,maxi,cl: Integer;
  maxrxl: Integer;
  Liste1: Tstringlist;
  Liste2: Tstringlist;

begin
 Screen.Cursor:=crHourglass;
 DecimalSeparator:='.';
 liste1:=Tstringlist.Create;
 liste1.LoadFromFile(OpenDialog1.FileName);
 l:=liste1.Count;
 progressbar1.Min:=-l;
 progressbar1.Max:=0;
 liste2:=Tstringlist.Create;
 liste2.add('lon'+chr(9)+'lat'+chr(9)+'RXL'+chr(9)+'CID'+chr(9)+'BCCH');
 repeat
  suchkoor:=copy(Liste1[1],1,GetPosNumX(chr(9),Liste1[1],2)-1);
  k:=0;
  i:=1;
  repeat
      if (pos(suchkoor,liste1[i])>0) then
      begin
        koor[k]:=liste1[i];
        k:=k+1;
        liste1.Delete(i);
        i:=i-1;
      end;
      i:=i+1;
      cl:=Liste1.Count;
  until i=cl;
  maxrxl:=-200;
  maxi:=0;
  progressbar1.position:=-cl;
  if k=1 then
  begin
    liste2.Add(koor[0]);
  end
  else if k>1 then
   begin
     for j := 0 to k - 1 do
     begin
       rxl:=copy(koor[j],GetPosNumX(chr(9),koor[j],2)+1,GetPosNumX(chr(9),koor[j],3)-GetPosNumX(chr(9),koor[j],2)-1);
       if strtoint(rxl)>maxrxl then
       begin
        maxrxl:=strtoint(rxl);
        maxi:=j;
       end;
     end;
     liste2.Add(koor[maxi]);
   end;
 until liste1.Count=1;
 liste2.SaveToFile(extractfilepath(OpenDialog1.FileName)+'Best.txt');
 liste1.Destroy;
 liste2.Destroy;
 Screen.Cursor:=crDefault;
end;
Die Daten sind Messwerte von Handys.

Gruß
Carsten

Jelly 17. Mär 2007 15:01

Re: Prozedur zu langsam, Optimierung nötig
 
Kannst Du mal genau sagen, was dein Algorythmus mit den Daten berechnet. Vielleicht findet sich ja auf der Ebene etwas viel Performanteres.

Hawkeye219 17. Mär 2007 16:36

Re: Prozedur zu langsam, Optimierung nötig
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Carsten,

ich habe meinen Vorschlag (Beitrag #10) einmal mit zufälligen Daten getestet (E6600-CPU, 2 GByte RAM):

Code:
 25000 Zeilen: Laufzeit < 0.2 sec
 50000 Zeilen: Laufzeit < 0.4 sec
100000 Zeilen: Laufzeit < 0.8 sec
Die Anwendung der Klasse TSparseMatrix ist denkbar einfach:

Delphi-Quellcode:
var
  M : TSparseMatrix;
begin
  M := TSparseMatrix.Create;
  try
    // Originaldatei laden
    M.LoadFromFile ('gps-original.txt');
    // Ergebnis speichern
    M.SaveToFile ('gps-optimized.txt');
  finally
    M.Free;
  end;
end;
Im Anhang findest du eine neue Version, die zwei Fehler korrigiert. Zum einen fehlte eine Initialisierung der Matrixelemente, wodurch negativen RXL-Werte falsch behandelt wurden. Zum anderen erforderte die fehlerhafte Implementierung der Val()-Routine in Delphi eine Nachbehandlung beim Zerlegen der Datenzeilen. Beim Testen konnte ich - abgesehen von der Sortierung - keine Unterschiede in den Ergebnissen beider Verfahren feststellen.

Wenn du Fragen zum Algorithmus hast, kannst du sie gerne hier stellen.

Gruß Hawkeye

carknue 17. Mär 2007 18:43

Re: Prozedur zu langsam, Optimierung nötig
 
@Hawkeye
Ich verstehe nicht ganz, was ich mit der Liste mit allen Elementen einer y-Koordinate soll? Ich brauche doch eher eine Liste mit allen Elementen einer x,y Kombination :gruebel:

Hawkeye219 17. Mär 2007 19:23

Re: Prozedur zu langsam, Optimierung nötig
 
Im Prinzip wird mit den Stringlisten eine zweidimensionale Matrix simuliert. Die Stringliste FLines enthält die y-Koordinaten (als String) und im Objects[]-Feld für jedes Element eine weitere Stringliste, welche die Daten aller (x,y)-Paare aufnimmt, die zur jeweiligen y-Koordinate gehören. Jedes Matrix-Element vom Typ TItem enthält den Wert RXL und den Zeilenrest tail, der nicht weiter ausgwertet werden muß.

Beim Einlesen der Originaldatei wird jede Zeile zunächst zerlegt (x, y, RXL, Zeilenrest). Mit den Koordinaten x und y wird dann in der Methode GetItem das zugehörige Matrixelement bestimmt. Dazu wird die y-Koordinate als String formatiert, der dann in der Liste FLines gesucht wird. Ist der String nicht vorhanden, wird ein neues Listenelement (= neue Matrixzeile) angelegt. In der Eigenschaft Objects[] des gefundenen bzw. neu angelegten Elements finden wir die Stringliste mit allen Elementen dieser Matrixzeile. Diese Liste durchsuchen wir mit der formatierten x-Koordinate und erzeugen, falls wir nichts finden, ein neues Element. Am Ende dieser zweistufigen Operation haben wir einen Zeiger auf ein Matrixelement (TIem) und können dessen Eigenschaft RXL prüfen und ggg. aktualisieren. Die Matrix speichert also jedes vorkommende (x,y)-Paar nur ein einziges Mal, es wird aber nicht für jedes mögliche Paar ein Speicherplatz angelegt. Alle Listen sind sortiert, es kann also jeweils eine schnelle binäre Suche durchgeführt werden.

Man könnte das sicher auch mit einer einfachen Liste lösen, indem man die Paare (x,y) als Index verwendet. Vielleicht ergeben sich ähnliche Laufzeiten - ich habe es nicht getestet.

Gruß Hawkeye

carknue 17. Mär 2007 21:55

Re: Prozedur zu langsam, Optimierung nötig
 
Nun habe ich die stringliste mal einfach mit liste1.sort sortiert. Die Suche kann nun sofort beendet werden, wenn es keine Übereinstimmung der Koordinaten gibt. Das gefundene wird ebenfalls sofort gelöscht. Nun dauert es nur noch 10 Sekunden auf dem E6600. Allerdings habe ich nun ein anderes Problem. Die liste.sort Funktion scheint den String irgendwie zu verändern. Im Editor sehen die beiden Ausgangs Dateien zwar gleich aus, MapInfo erkennt aber beim Einlesen die Werte alle nur noch als Zeichen. Ohne sort erkennt es die Koordinaten als Float und RXL als Integer. Kann man zwar hinterher wieder ändern, ist aber mehr Aufwand. Allerdings geht das Zeichnen dafür bei der sortierten Liste deutlich schneller. Was verändert sort am Format?

Delphi-Quellcode:
procedure TForm1.Button8Click(Sender: TObject);
var
  rxl: string;
  suchkoor: string;
  Koor: Array[0..1000] of string[35];
  i,l,k,j,maxi,cl: Integer;
  maxrxl: Integer;
  Liste1: Tstringlist;
  Liste2: Tstringlist;

begin
 Screen.Cursor:=crHourglass;
 DecimalSeparator:='.';
 liste1:=Tstringlist.Create;
 liste1.LoadFromFile(OpenDialog1.FileName);
 // Jetzt wird sortiert
 liste1.sort;
 l:=liste1.Count;
 progressbar1.Min:=-l;
 progressbar1.Max:=0;
 liste2:=Tstringlist.Create;
 liste2.add('lon'+chr(9)+'lat'+chr(9)+'RXL'+chr(9)+'CID'+chr(9)+'BCCH');
 repeat
  suchkoor:=copy(Liste1[1],1,GetPosNumX(chr(9),Liste1[1],2)-1);
  k:=0;
  i:=1;
  repeat
      if (pos(suchkoor,liste1[i])>0) then
      begin
        koor[k]:=liste1[i];
        k:=k+1;
        liste1.Delete(i);
        i:=i-1;
      end
     //neuer else zweig zum Abbruch der Suche
      else i:=liste1.Count-1;
      i:=i+1;
      cl:=Liste1.Count;
  until i=cl;
  maxrxl:=-200;
  maxi:=0;
  progressbar1.position:=-cl;
  if k=1 then
  begin
    liste2.Add(koor[0]);
  end
  else if k>1 then
   begin
     for j := 0 to k - 1 do
     begin
       rxl:=copy(koor[j],GetPosNumX(chr(9),koor[j],2)+1,GetPosNumX(chr(9),koor[j],3)-GetPosNumX(chr(9),koor[j],2)-1);
       if strtoint(rxl)>maxrxl then
       begin
        maxrxl:=strtoint(rxl);
        maxi:=j;
       end;
     end;
     liste2.Add(koor[maxi]);
   end;
 until liste1.Count=1;
 liste2.SaveToFile(extractfilepath(OpenDialog1.FileName)+'Best_sorted.txt');
 liste1.Destroy;
 liste2.Destroy;
 Screen.Cursor:=crDefault;
end;

grenzgaenger 18. Mär 2007 14:12

Re: Prozedur zu langsam, Optimierung nötig
 
zeig doch mal her, wie sortierst du die tlist?

persönlich hab ich keine ahnung was du mit den vielen dateien oder tlist alles machst und im speicher braucht man das ja auch nicht behalten. du brauchst ja nur einmal deine datei durchzugehen, dir die jeweils besten werte merken und das ergebnis ausgeben... das sollt recht schnell gehen. im pseudocode sieht das in etwa so aus

Code:
öffne quelldatei;
while not eof(quelldatei) do
begin
 lese datensatz(quelldatei) und positioniere auf nächsten satz;
 bereite datensatz auf;
 prüfe ob datensatz im buffer
 wenn ja dann
  prüfe ob datensatz besser als der im buffer
  wenn nicht dann
   nimm neue daten in buffer auf;
 wenn nicht im buffer dann
  nehme datensatz in den buffer auf;//an der richtigen stelle
end;
schliesse quelldatei;
der buffer muss natürlich sortiert sein, am besten baust du dir dafür einen binary tree auf, wo du sehr schnell auf die einzelnen elemente zugeifen kannst. alternativ, gings auch mit 'ner TList ist aber nicht optimal. hier musst gehirnschmalz investieren, damit tlist beim einfügen an einer bestimmten stelle nicht jedesmal den speicher umschichtet und du die sanduhr zu sehen bekommst.

<HTH>

grenzgaenger 18. Mär 2007 16:14

Re: Prozedur zu langsam, Optimierung nötig
 
Liste der Anhänge anzeigen (Anzahl: 1)
hier 'n bislerl code, auf der basis von objekten, weiss nicht, ob ich deine anforderungen getroffen hab...

Delphi-Quellcode:
program test;
{$APPTYPE CONSOLE}
uses
  sysutils,
  contnrs;

type
 tRec = class(tobject)
  keystr: string;
  ion, lat: real;
  rxl, cid, bcch: integer;
  procedure copystr(s: string);
  procedure assign(const r: tRec);
 end;

 trList = class(tobjectlist)
  procedure update(const ORec: tRec);
  procedure print;
 end;

procedure tRec.assign(const r: tRec);
begin
 keystr := r.keystr;
 ion   := r.ion;
 lat   := r.lat;
 rxl   := r.rxl;
 cid   := r.cid;
 bcch  := r.bcch;
end;

procedure tRec.copystr(s: string);
var
 i: integer;
begin
 i := pos(#9,s);
 ion := strtofloat(copy(s,1,i-1));
 delete(s,1,i);
 i := pos(#9,s);
 lat := strtofloat(copy(s,1,i-1));
 delete(s,1,i);
 i := pos(#9,s);
 rxl := strtoint(copy(s,1,i-1));
 delete(s,1,i);
 i := pos(#9,s);
 cid := strtoint(copy(s,1,i-1));
 delete(s,1,i);
 bcch := strtoint(s);
 keystr := format('%3.6f|%3.6f',[ion, lat]); //ggf. anpassen
end;

{ trList }
function compare(Item1, Item2: Pointer): Integer;
begin
 if tRec(item1).keystr = tRec(item2).keystr then
  result := 0
 else
  if tRec(item1).keystr < tRec(item2).keystr then
   result := -1
  else
   result := 1;
end;

procedure trList.update(const ORec: tRec);
 procedure search(l,r: integer; var found: boolean; var aktuell, direction: integer);
 var
  c,i: integer;
 begin
  if not found and (l<r) then
  begin
   i := (l+r) shr 1;
   c := compare(orec, items[i]);
   direction := c;
   if c = 0 then
   begin
    found := true;
    aktuell := i;
   end
   else
    if c>0 then
    begin
     aktuell := i;
     search(i+1,r,found,aktuell,direction);
    end
    else
    begin
     aktuell := i;
     search(l,i-1,found,aktuell,direction);
    end;
  end;
 end;

var
 r: tRec;
 i,c: integer;
 found: boolean;
begin
 found := false;
 i := -1;
 if count > 0 then
  search(0,count,found,i,c);

 if found then
 begin
  if oRec.rxl > tRec(items[i]).rxl then //gff. anpassen
  begin
   tRec(items[i]).rxl := orec.rxl;
   tRec(items[i]).cid := oRec.cid;
   tRec(items[i]).bcch:= orec.bcch;
  end;
 end
 else
 begin
  r := tRec.Create;
  r.assign(oRec);

  if i < 0 then i := 0;

  if (c>0) and (i=count-1) then i := count;
  if (c>0) and (i<count) then inc(i);
  if (i>0) and (compare(orec, items[i-1])<0) then dec(i);

  insert(i,r);
 end;
end;

procedure trList.print;
var
 i: integer;
begin
 for i := 0 to count - 1 do
  writeln('>',i:3,#9,
          trec(items[i]).ion:3:4, #9,
          trec(items[i]).lat:3:4, #9,
          trec(items[i]).rxl, #9,
          trec(items[i]).cid, #9,
          trec(items[i]).bcch);
end;

var
 f       : text;
 s       : string;
 tl      : TRList;
 tmpRec  : tRec;
 firstline: boolean;
begin
 DecimalSeparator:='.';
 firstline := true;
 tmpRec:= tRec.create;
 tl   := TRList.Create;
 AssignFile(f, 'c:\prj\test\test.txt');
 Reset(f);

 while not eof(f) do
 begin
  readln(f,s);
  if not firstline then
  begin
   tmpRec.copystr(trim(s));
   tl.update(tmpRec);
  end
  else
   firstline := false;
 end;
 tl.print;

 close(f);
 tmpRec.free;
 tl.Free;


 readln;
end.
Edit: aktualisierte version, da beim sort noch ein paar unstimmigkeiten vorhanden waren.

ps: hier wird die meiste zeit, ca. 2,3, 4 sekunden für die ausgabe der berechneten werde (120'0000) benötigt. die verarbeitung erfolgt binnen 1, 2 senkunden...


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:56 Uhr.

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