Handhabung und Verarbeitung größere Datenmengen

Rund um die LCL und andere Komponenten
Antworten
hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Handhabung und Verarbeitung größere Datenmengen

Beitrag von hubblec4 »

Hallo Lazarusgemeinde

Hättet ihr vielleicht ein paar Ratschläge für mich?

Worum geht es?

Ich mus die Sprach-Codes nach ISO-639-2 (484 Codes) und die Länder Codes nach ccTLD (251 Codes) in meinem Tool verarbeiten.
Der Benutzer kann aus einer ComboBoxEx(CBE) die Einträge auswählen(Sprach/Länder-Code(SL-Codes) mit Bezeichnung ). (Für eine später Speicherung wird nur der SL-Code verwendet.)

In einem VirtualStringTree(VST) gibt es mehrere Nodes wo dann die SL-Codes getrennt gespeichert werden (also nicht direkt in den Nodes dafür gibt es Datenklassen).

Auf jedenfall, muss bei einem neu ausgwählten Node die CBE auf den entsprechenden SL-Code eintrag eingestellt werden.

Bei einer CBE gibt es irgendwie nicht die function IndexOf() und selbst wenn, macht diese Funktion aus nichts anderes als die Einträge durchgehen und prüfen ob der String übereinstimmt -> was ein bissl dauert wenn es der letzte Eintrag ist.
Abgesehen davon würde das auch so nicht recht funktionieren, da ich ja als gespeicherten Datensatz nur den SL-Code habe und nicht die volle Bezeichung.
Da würde mir IndexOf() auch nur -1 liefern.

Alernative hatte ich daran gedacht einen weiteren Datensatz zu speichern der den ItemIndex von der CBE darstellt.
Allerdings würde das nur dann funktionieren wenn man nur einen einzigen SL-Code auswählen kann.
Es ist aber möglich in der CBE mehrere SL-Codes anzuhaken und zu speichern. -> Dann würde mir einfallen, eben alle diese ItemIndexe von den angehakten Einträgen zuspeichern.
Aber wie am besten?
Ein dynamisches array?, mag ich irgendwie nicht wirklich.
Eine IntegerList (habe ich mal gesucht und gefunden)?

Das alles würde soweit aber nur funktionieren wenn das mit den SL-Codes statisch wäre, da man aber als Benutzer einfluss auf die Reihenfolge, und sogar die Anzahl der angezeigten SL-Codes hat, gestalltet es sich dann doch etwas schwierger (für mich).


Was hätte ich gerne.

Wenn ich einen neuen Node selektiere, hole ich mir die SL-Codes Daten(ger eng ita) und dann ohne viel zu rechnen einen ItemIndex(mehrere Indexe) um die CBE einzustellen. Denn es gibt ja auch gleich zwei CBE's Sprache und Länder.

Überlegt hatte ich mir die SL-Codes mit einer case-of Anweisung zu verarbeiten. Geht aber auch nicht so einfach wegen den veränderbaren SL-Code Idexen in der CBE.
Nun wollte ich jedem SL-Code ein ArrayFeld in einem IntegerArray zuweisen worin dann der aktuelle CBE-Index steht (das IntegerArray kann ich dann immer erneueren wenn der Benutzer etwas geändert hat).

Naja irgendwie habe ich das Gefühl nicht recht weiter zu wissen oder mich irgendwie verrannt zu haben.

Könntet ihr mir ein paar tipps geben wie man so etwas angeht.

hier noch ein bissl QuellCode:

Code: Alles auswählen

 
type
  TIndexLanguages = array[0..483] of Integer;
var
  LanguagesIdx: TIndexLanguages;
 
// Get - Sprach Array Index
GetLngArrayIdx(const aLng: String): Integer;
begin
  case aLng of                                  // Lng auswerten
   '','und': Result:=0;
   'aar': Result:=1;
   'abk': Result:=2;
   'ace': Result:=3;
   'ach': Result:=4;
   'ada': Result:=5;
   .....
  'znd': Result:=479;
   'zul': Result:=480;
   'zun': Result:=481;
   'zxx': Result:=482;
   'zza': Result:=483;
  end;
 
// Get - Sprach ItemIndex für CoB's, CBE's
GetLngItemIndex(const aLng: String): Integer;
begin
  Result:=LanguagesIdx[GetLngArrayIdx(aLng)];
end
 
 
// CBE Index einstellen (nur als beispiel - und nur für einen Index)
procedure SetCBEIndex;
begin
   CBE_Lng.ItemIndex:=GetLngItemIndex(eng);
end;
 
 
 


Wie steht es denn um eine solche case-of Anweisung mit sehr vielen "Einträgen", mit der Geschwindigkeit. Ich hatte beim Debuggen schon das Gefühl das es etwas dauert (nach F8 drücken) bis die nächste Zeile selketiert wird.


hubble

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von Socke »

Kannst du dem VST nicht noch zusätzliche Daten anhängen?

Alternativ solltest du dir eine Baumstruktur aufbauen, in der du suchen kannst:

Code: Alles auswählen

a...........z
|           |
a..b..c     n...u..
|  |  |     |   |
r  k  e..h  d   l
|  |  |  |  |   |
1  2  3  4  479 480

Somit bist du bei jedem Code in 4 Operationen am Ziel bei konstanter Zeit über alle Codes.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von hubblec4 »

Hi Socke

Ja die Nodes enthalten auch ein Record welches Daten enthält, diese sind aber nur für die VST-Node ansich gedacht. Also zum beispiel der Node.Text oder ein ImageIndex für die Node-Icons.

Das mit der Baumstruktur ging mir auch schon durch den Kopf.
Müsste ich dann für den 1.Buchsaben eine case-of Anweisung definieren, für den 2. und 3. Buchstaben ebenfalls.

Code: Alles auswählen

 
case Lng[1] of
 'a': case Lng[2] of
       'a': case Lng[3] of
             'r': Result:=1;
 
            end;
      end
 
end;
 


Würde das nicht auch recht groß werden und dreimal durch die case-of Anweisung rattern braucht doch auch seine Zeit.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von Socke »

hubblec4 hat geschrieben:

Code: Alles auswählen

 
case Lng[1] of
 'a': case Lng[2] of
       'a': case Lng[3] of
             'r': Result:=1;
 
            end;
      end
 
end;
 

Würde das nicht auch recht groß werden und dreimal durch die case-of Anweisung rattern braucht doch auch seine Zeit.

An diesen Ansatz hatte ich gar nicht gedacht ;-) Hier kann der Code in der Tat ein wenig unübersichtlich werden und sollte daher unbedingt in eine eigene Funktion ausgelagert sein.
Der Vorteil hier ist, dass auf jeder Ebene nur maximal 26 Varianten sind, d.h. es werden maximal 26*3=78 Bedingenen (worst Case) geprüft und nicht alle Ländercodes.

Ich hatte eher an Arrays gedacht; in den Arrays werden neben den Buchstaben auch ein Zeiger auf das Array der nächsten Ebene hinterlegt. Wenn die Arrays immer alle 26 Zeichen von a bis z enthalten, kannst du die Position im Array sehr einfach aus dem ASCII-Code des Zeichens berechnen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

BeniBela
Beiträge: 308
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von BeniBela »

Dafür gibt es doch Hashmaps. Für kurze Strings eignet sich contnrs.TFPHashList

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von hubblec4 »

Hi Socke.

Könntest du mir das mit dem Aufbau für die Arrays etwas detalierter hier posten (wenns keine Umstände macht)?

Das mit den case-of Verzweigungen werde ich mir nochmal genauer anschauen. Dachte auch an den Vorteil das es nur 3*26 Bedingungen sind.
(Allerdings riesiger Quellcode - aber das ist egal wenns schneller wird.)

Ich habe jetzt erstmal meinen beschrieben Weg ausprobiert. Die case-of Anweisung "rattert" durch die 484 Einträge und gibt mir den entsprechenden ArrayIndex wo dann der aktuelle CBEIndex steht.
Das ganze geht recht fix - schneller als 484 Einträge durch gehen und die Captions(welche nicht nur aus dem SL-Code besteht) vergleichen.

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von hubblec4 »

BeniBela hat geschrieben:Dafür gibt es doch Hashmaps. Für kurze Strings eignet sich contnrs.TFPHashList


Danke für den Hinweis, leider sagt mir das jetzt im ersten Moment recht wenig. (Belese mich da aber gern)

Könntest du das etwas ausführlicher erklären?

BeniBela
Beiträge: 308
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von BeniBela »

Das ist eine Standardklasse wie TStringList nur schneller

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von hubblec4 »

BeniBela hat geschrieben:Das ist eine Standardklasse wie TStringList nur schneller


Ok. Hatte mir den QuellCode schon etwas angeschaut.
Da es wie eine StringList funktioniert solte die Handhabung nicht schwer sein.

Müsste ich dann mal testen was schneller läuft, die TFPHashList oder die case-of Anweisungen.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von Socke »

Socke hat geschrieben:Ich hatte eher an Arrays gedacht; in den Arrays werden neben den Buchstaben auch ein Zeiger auf das Array der nächsten Ebene hinterlegt. Wenn die Arrays immer alle 26 Zeichen von a bis z enthalten, kannst du die Position im Array sehr einfach aus dem ASCII-Code des Zeichens berechnen.


hubblec4 hat geschrieben:Könntest du mir das mit dem Aufbau für die Arrays etwas detalierter hier posten (wenns keine Umstände macht)?

Mir ist eine viel einfachere Möglichkeit eingefallen, auch wenn hier ein paar Bytes verschwendet werden.

Code: Alles auswählen

program Project1;
 
uses
  sysutils;
 
type
  // durch String mit definierter Länge entfallen alle Prüfungen auf die Länge
  TLngCode = string[3];
 
var
  // nicht genutze Zeichen verbrauchen ein paar Bytes mehr Speicher,
  // dafür ist die Zugriffszeit konstant
  // Den Datentyp für den Zahlwert könnte man z.B. auch kleiner (ShortInt)
  // wählen.
  data: array['a'..'z'] of array['a'..'z'] of array['a'..'z'] of Integer;
 
// Validierung um die Array-Grenzen einzuhalten
function ValidLngCode(const aLngCode: TLngCode): Boolean;
begin
  Result := (aLngCode[1] in ['a'..'z']) and
            (aLngCode[2] in ['a'..'z']) and
            (aLngCode[3] in ['a'..'z']);
end;
 
// Hilfsfunktion um den Daten-Array zu befüllen
procedure SetValue(const aLng: TLngCode; aValue: Integer);
begin
  if ValidLngCode(aLng) then
    data[aLng[1]][aLng[2]][aLng[3]] := aValue
  else
    raise Exception.CreateFmt('Ungültiger Sprach-Code: %s', [aLng]);
end;
 
procedure InitialzeData;
begin
  // alle nicht gesetzen Sprache-Codes sind = 0
  FillByte(data['a', 'a', 'a'], sizeof(data), 0);
  // bekannte Werte definieren
  SetValue('aar',   1);
  SetValue('abk',   2);
  SetValue('ace',   3);
  SetValue('ach',   4);
  SetValue('ada',   5);
  //...
  SetValue('znd', 479);
  SetValue('zul', 480);
  SetValue('zun', 481);
  SetValue('zxx', 482);
  SetValue('zza', 483);
end;
 
// Wert ermitteln
function GetValue(const aLng: TLngCode): Integer;
begin
  if ValidLngCode(aLng) then
    Result := data[aLng[1]][aLng[2]][aLng[3]]
  else
    raise Exception.CreateFmt('Ungültiger Sprach-Code: %s', [aLng]);
end;
 
begin
  InitialzeData;
  Writeln('Value von zza: ', GetValue('zza'));
 
  readln;
end.

Die Funktion GetValue() arbeitet praktisch mit einem direkten Array-Zugriff auf den Ergebniswert. Der Zugriff ist schneller als jede Hashmap, da die Position im Array nicht berechnet werden muss.

Edit: Anstatt der Initialisierungsprozedur könnte man auch einen konstanten Array verwenden. Die Deklaration ist dann zwar ein wenig unübersichtlich, jedoch wir der Array dann schon zur Übersetzungszeit zusammengebaut, sodass hier keine Zeit beim Programmstart benötigt wird.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Handhabung und Verarbeitung größere Datenmengen

Beitrag von hubblec4 »

Danke für die ausfürhliche und anschauliche Erklärung.

Ich werde mir das auch genauer anschauen. (Habe aber erst nächste Woche wieder Zeit.)
Gerade FillByte() kenne Ich noch nicht, sieht aber schick aus.

Antworten