Autor Beitrag
moloch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Fr 09.12.05 14:04 
Hallo,
bisher habe ich es so gemacht das ich meine daten in ein dynamisches Array geladen habe.
wenn ich jetzt eine Information zu einer zeile haben wollte bin ich das array mit einer schleife durchgegangen und dann die nötigen infos letztendlich gefunden.
bei einer datenmänge von ca 50000 datensätzen wird das jedoch immer langsamer. bei java gibt es das objekt hashmap soweit ich weiss und das soll dieses problem besser lösen können.
die frage ist einfach ob es in delphi auch eine schnellere möglichkeit gibt auf die jeweiligen daten zuzugreifen als mit der bisherigen methode von mir.

mfg
moloch
chrisw
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 439
Erhaltene Danke: 3

W2K
D7
BeitragVerfasst: Fr 09.12.05 14:07 
Bei 50000 Datensätzen, denke ich, sollte man zumindest über eine Datenbanklösung nachdenken !

_________________
Man sollte keine Dummheit zweimal begehen, die Auswahl ist schließlich groß genug.
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8549
Erhaltene Danke: 478

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Fr 09.12.05 14:12 
Schon mal daran gedacht, das Array zu sortieren, und dann eine Binärsuche drauf anzusetzen?

_________________
We are, we were and will not be.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Fr 09.12.05 14:15 
chrisw: Ist ne DB dafür nicht ein bisschen übertrieben.

Also ich weiß nicht was genau Java da macht aber ein paar Text Beispiele wären nicht schlecht. Ich habe auf meiner Webseite aber auch eine HashKlasse bereit gestellt. Mit dieser kannst du zu einem eindeutigen Text einen Pointer ablegen.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Fr 09.12.05 15:44 
hallo also noch mal zum besseren verständnis meiner vorgehensweise.

DB ist z.B. MSSQL

Jetzt lade ich mir per sql befehl daten in mein dynamisches array.

so und jetzt geht es darum dass ich wärend das programm läuft aus verschiedenen gründen auf bestimmte datensätze zugreifen möchte. z. b. um die daten anzuzeigen in einer oberfläche.

der bisherige weg war dann der:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function Get_Daten(ID : Integer) : String;
begin
  for i:= (arrayto (arraydo begin
    if (array[i].id <> id) then continue;
     
    result := array[i].name;
    break;
  end;
end;


so und ich suche jetzt eine schnellere lösung.

Moderiert von user profile iconraziel: Delphi-Tags hinzugefügt.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Fr 09.12.05 17:25 
kannst du mir ein beispiel geben wie ich mit deiner hashmap lösung umgehen könnte
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Mo 12.12.05 11:14 
Sorry das es ein bisschen gedauert hat. War übers WE nicht im Forum.

Ich weiß jetzt nicht was du vor hast darin abzulegen. Also ob es sich nur im einen einzelnen Text der eine Record handelt. Bei beiden musst du aber beachten, dass du in dem Hash ausschließlich nur den Pointer von etwas ablegen kannst. Du musst entsprechende mit einem Pointertypen arbeiten und diesen erstellen und am Ende wieder frei geben.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
procedure TForm1.FormCreate(Sender: TObject);
begin
  // Hash erstellen
  fHash := TIntegerHash.Create(1000);
end;


procedure TForm1.FormDestroy(Sender: TObject);
var
  Idx: Integer;
  Vals: TList;
begin
  Vals := TList.Create;
  try
    // Alle Pointer von den Werten abholen.
    fHash.GetValues(Vals);

    // Strings frei geben.
    for Idx := 0 to Vals.Count -1 do
      StrDispose(PChar(Vals[Idx]));
  finally
    FreeAndNil(Vals);
  end;

  // Hash frei geben.
  FreeAndNil(fHash);
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  Text: String;
begin
  // Temporärer Text
  Inc(fCount);
  Text := 'Text' + IntToStr(fCount);

  // StrNew erstellt einen neuen Speicherbereich der den Text enthält.
  // PChar(Text) würde nicht gehen, da Text nur flüchtig ist und dann
  // ein ungültiger Pointer abgelegt werden würde.
  fHash.Add(fCount, StrNew(PChar(Text)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Idx, Num: Integer;
  Names: TList;
begin
  Memo1.Lines.BeginUpdate;
  try
    Memo1.Lines.Clear;

    Names := TList.Create;
    try
      // Alle Namen aus dem Hash holen.
      fHash.GetNames(Names);

      for Idx := 0 to Names.Count -1 do begin
        Num := Integer(Names[Idx]);

        // Eigentlich ist nur diese Zeile für dich wichtig.
        // einzelnen Wert Abholen und in Memo packen.
        Memo1.Lines.Add(IntToStr(Num) + #9 + PChar(fHash.Get(Num)));
      end;
    finally
      FreeAndNil(Names);
    end;
  finally
    Memo1.Lines.EndUpdate;
  end;
end;


Beim Erstellen des Hashs musst du eine Größe angeben. Die ist im nachhinein nicht änderbar außer man erstellt ein komplett neues Hash. Da die Werte intern mit der Größe verrechnet werden. Wenn deine IDs nicht gerade vortlaufend sind so passiert es häufig, dass jedes zweite, dritte oder vierte Feld leer bleibt. In einem Feld sind dann minilisten gespeichert. Wenn du eine Größe von 1 hast wären alle Werte in einer Liste gespeichert. Dann wäre es sogar noch langsamer als ein Array oder TList. Also musst du entsprechend viele Felder erstelen lassen um eine möglichst breite Streueung zu erhalten. Bei 50000 Datenfelder würde ich schon sagen eine größe um die 20000 wäre sinnvoll. Das sollte dann vom Speicherverbrauch auch noch halbwegs gehen. Primzahlen wird nachgesagt sich für solche Feldgrößen am Besten zu eignen.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Mo 12.12.05 16:53 
PByte
kennt mein delphi 5 leider nicht
vielleicht wird es noch mehr unbekanntes geben aber damit fängt der compiler an zu meckern
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Mo 12.12.05 17:09 
peinlich vergiss diese frage.
ok ich probier weiter...
danke erstmal für die hilfe ich sag bescheid wie ich damit voran komme
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mo 12.12.05 17:35 
Alternative zu den Integer-Hashtabellen sind die hier, die passen ihre Größe dynamisch an, natürlich als Primzahl.
@LossyEx: Schau doch mal in den Code hier und übernimm (von mir aus) die dynamische Größenveränderung. Deine String->Hash Funktion ist auch nicht die Beste (zumindest laut Literatur nicht). Nimm doch eine von Meinen, wenn Du willst. Deine Implementierung ist ja (logischerweise) fast identisch mit Meiner. Kein Wunder: Wir haben beide das beste Verfahren (chained hash). Ich habe noch einen Iterator, Du dafür ein paar andere Methoden... Beides zusammen wäre doch was.

Interessant sind auch Skiplisten, die bis ca. 50000 Elemente noch schneller als Hashetabellen sind (bei Strings). Code hab ich gerade nicht hier, sondern auf meinem Laptop. Bei Bedarf poste ich das aber gerne.
Einloggen, um Attachments anzusehen!
_________________
Na denn, dann. Bis dann, denn.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Di 13.12.05 10:23 
Habe mir die Theorie vor ein paar Jahren aus einem Algorithmenbuch angeeignet. Allerdings habe ich nur die ersten 4 Seiten der Hashs geschafft. Alles was dahinter kam war zu hoch für mich. Habe die Klassen dann mehr oder minder aus meinen Erinnerungen geschrieben. Aber werde mir das auf jeden Fall mal anschauen. :-) Kann allerdings noch nicht versprechen, dass ich etwas ändern werde, denn ich weiß noch nicht wann ich dafür dann zeit habe. Viele wichtige Dinge stehen an. :(

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Di 13.12.05 11:38 
hallo,
also das habe ich noch nicht ganz verstanden.

ich gehe wie folgt vor:

1.ich möchte ein vorhandenes dynamisches Array in ein Hash legen.

das würde dann so aussehen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
  i : Integer;
  Ptr : Pointer;
begin
    // Hash erstellen
    result := TStringHash.Create(length(HilfArr));

    // Hash füllen
    for i := low(HilfArr) to high(HilfArr) do begin

      result.Add(HilfArr[i].Name, HilfArr[i].ID, Ptr)
    end;
end;


das funktioniert so nicht. das liegt mit sicherheit daran das ich PTR also den Pointer nicht bestimme.wie geht das und wird es dann funktionieren oder hab ich noch was falsch gemacht?

Moderiert von user profile iconGausi: Delphi-Tags hinzugefügt.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Di 13.12.05 12:45 
Was befindet sich denn in dem Array? Also ich denke mal ein Record. Poste mal Bitte wie das aussieht, dann bekommste auch ein bissel Code.

Aber im Endeffekt würde ich soweiso sagen, dass du das Array komplett entfernen solltest und das Hash gleich von Begin an füllen solltest. Das ist wesentlich einfacher als erst das Array befüllen und das dann in das Hash zu kippen.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Di 13.12.05 13:04 
Name und ID dazu

ich will mit dem namen reingehen und die ID holen
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Di 13.12.05 13:46 
Also ich vertrete die Auffassung, dass eine Methode nur in sehr seltenen Fällen eine Klasse erstellen sollte und diese zurückgibt. Mit anderen Worten ich achte immer darauf, dass derjenige der irgendwelche Objekte erstellt diese auf wieder frei gibt. Bzw wenn er diese nicht freigeben kann, dass er sie auch nicht erstellt. Vermeidung von Speicherlöchern.

Zu deinem Code oberhalb. Wenn du es unbedingt so machen möchtest solltest du aber auch darauf achten, dass du Fehler abfängst und entsprechend darauf reagierst. Eine sehr gute Möglichkeit dazu wäre Try Except bzw Try Finally.

Wenn ich das richtig verstanden habe möchtest du anhand der Namen eine ID auswählen können? Einen Integer kannst du nicht direkt ablegen, da Integer und Pointer aber beide 32 Bit groß sind können die sich den Speicherplatz teilen.

Hier mal der veränderte Code.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
  i : Integer;
begin
  // Hash erstellen
  // Damit es nicht ganz so groß wird. Aber es wäre eh besser, wenn das Hash direkt befüllt würde.
  result := TStringHash.Create(length(HilfArr) div 3);
  try

    // Hash füllen
    for i := low(HilfArr) to high(HilfArr) do 
      result.Add(HilfArr[i].Name, Pointer(HilfArr[i].ID))

// Zum Auslesen.
//    Integer(Hashklasse.Get('Blahh'));

// Du solltest im übrigen die ID 0 nicht benutzen. Da es sonst zu Problemen kommt,
// da ein nil pointer gar nicht erst im Hash abgelegt werden. Pointer(0) wäre nil.
// Außerdem liefert Get nil zurück sobald der Name nicht existiert. Und damit wären alle nicht
// gefunden Namen automatisch ID 0.
  except
    // Es ist ein Fehler aufgetreten
    on e:exception do begin
      // Hash freigeben
      FreeAndNil(Result);

      // Fehler neu auslösen
      raise e;
    end;
  end;
end;

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Mi 14.12.05 14:25 
also ich habs so hinbekommen
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
    // Hash erstellen
    result := TStringHash.Create(length(HilfArr));

    // Hash füllen
    for i := low(HilfArr) to high(HilfArr) do begin
      GetMem(Ptr, sizeof(TIdRec));
      Ptr^.ID := HilfArr[i].ID;

      result.Add(HilfArr[i].Name, Ptr);
    end;


Moderiert von user profile iconTino: Delphi-Tags hinzugefügt.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Mi 14.12.05 14:49 
Bitte benutz die Delphi-tags. Ich denke mal die Mods haben besseres zu tun als ständig die Tags bei dir einfügen zu müssen. ;-)

Okay. Vom Prinzip her geht es auch. Aber du hast so ein paar Nachteile. Du musst beim Beenden auf jeden Fall alle Pointer mit GetValues in eine TList holen und diese dann auch wieder frei geben. Außerdem benutzt ein komplexes Record um eine einfache Zahl abzulegen. In dem Record enthalten ist dann aber auch noch ein ungenutzter Text. Sozusagen verschwendest du derzeit pro Eintrag 8 Bytes Speicher was dir aber keinen Vorteil bringt. Nach außen hin dürfte es sowieso auch keinen Unterschied machen.

Aber ist deine Anwendung kannste also auch so lassen.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Mi 14.12.05 16:09 
aber wenn ich das programm beende wird der speicher von selbst frei gemacht.oder täuscht das nur.
moloch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 451

Win 2000
D5 Prof
BeitragVerfasst: Mi 14.12.05 16:13 
und wieso verschwende ich damit speicher.das hab ich nicht ganz verstanden
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Mi 14.12.05 16:23 
Windows räumt dann alles weg was noch da ist. Aber das ist nicht die beste Einstellung. Es handelt sich dennoch um Leichen. Wenn du diese bis zu letzt benutzt mag das nicht so schlimm sein aber solltest du sie nur kurz benutzen, dann solltest du sie auf jeden Fall wieder frei geben. Wobei ich der Meinung bin, dass man IMMER alles wieder freigeben sollte.

Das mit dem Speicher verschwenden ist einfach. Mit meiner Lösung würde ich lediglich den Pointer benutzen um die ID abzulegen. Du erstellst aber einen extra Speicherbereich in dem du die ID ablegst und benutzt den Pointer des Spiechers. Dadurch, dass du sogar das Record erstellst hast du auch noch einen Pointer auf den String bei jedem eintrag dabei. Und auch diese Pointervariable muss irgendwo Speicher belegen.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.