Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi "Array" mit Strings als Indizes (Zuordnungstabelle) (https://www.delphipraxis.net/130919-array-mit-strings-als-indizes-zuordnungstabelle.html)

blackdrake 15. Mär 2009 20:45


"Array" mit Strings als Indizes (Zuordnungstabelle
 
Wer viel mit PHP zu tun gehabt hat, wird bei Delphi sicherlich dynamische Arrays vermissen, die Strings als Indizes haben. Da ich gerade an einem Projekt arbeite, bei dem der Benutzer einem Objekt einen konkreten Name-Identifier geben soll, habe ich mal eine Klasse erstellt, die einen String ein TObject zuweist. Dieses TObject kann man dann mit konkreten Instanzen einer TObject-Ableitung belegen (z.B. einer TImage-Instanz).

Delphi-Quellcode:
interface

uses
  Contnrs;

type
  TEasyObjectManager = class(TObject)
  published
    constructor Create;
    destructor Destroy; override;
  public
    function GetValue(Name: string): TObject;
    procedure SetValue(Name: string; Value: TObject);
    function ValueExists(Name: string): boolean;
    procedure DeleteValue(Name: string);
    function Count: integer;
    function GetValueById(Index: integer): TObject;
  private
    List: TObjectList;
  end;

implementation

type
  TNameObjectPair = class(TObject)
    Name: string;
    Value: TObject;
  end;

(*** TEasyObjectManager ***)

constructor TEasyObjectManager.Create;
begin
  inherited;
  // OwnsObject ist false. Das heißt, die Objekte, die wir verwalten,
  // werden nicht freigegeben.
  List := TObjectList.Create(false);
end;

destructor TEasyObjectManager.Destroy;
begin
  if Assigned(List) then List.Free;
  inherited;
end;

function TEasyObjectManager.GetValue(Name: string): TObject;
var
  i: integer;
begin
  result := nil;
  for i := 0 to List.Count-1 do
  begin
    if TNameObjectPair(List.Items[i]).Name = Name then
    begin
      result := TNameObjectPair(List.Items[i]).Value;
      break;
    end;
  end;
end;

procedure TEasyObjectManager.SetValue(Name: string; Value: TObject);
var
  i: integer;
  n: TNameObjectPair;
  found: boolean;
begin
  found := False;
  for i := 0 to List.Count-1 do
  begin
    if TNameObjectPair(List.Items[i]).Name = Name then
    begin
      TNameObjectPair(List.Items[i]).Value := Value;
      found := true;
      break;
    end;
  end;
  if not found then
  begin
    UniqueString(Name);
    n := TNameObjectPair.Create;
    n.Name := Name;
    n.Value := Value;
    List.Add(n);
  end;
end;

function TEasyObjectManager.ValueExists(Name: string): boolean;
var
  i: integer;
begin
  result := false;
  for i := 0 to List.Count-1 do
  begin
    if TNameObjectPair(List.Items[i]).Name = Name then
    begin
      result := true;
      break;
    end;
  end;
end;

procedure TEasyObjectManager.DeleteValue(Name: string);
var
  i: integer;
begin
  for i := 0 to List.Count-1 do
  begin
    if TNameObjectPair(List.Items[i]).Name = Name then
    begin
      List.Delete(i);
      break;
    end;
  end;
end;

function TEasyObjectManager.Count: integer;
begin
  result := List.Count;
end;

function TEasyObjectManager.GetValueById(Index: integer): TObject;
begin
  result := List.Items[Index].Value;
end;
Ein Anwendungsbeispiel:

Delphi-Quellcode:
var
  x: TEasyObjectManager;
begin
  x := TEasyObjectManager.Create;
  try
    x.SetValue('foo', Form1); // foo wird angelegt
    ShowMessage(TForm(x.GetValue('foo')).Caption);
    x.SetValue('foo', Button1); // foo wird überschrieben
    ShowMessage(TButton(x.GetValue('foo')).Caption);
  finally
    x.Free;
  end;
end;
Anmerkung: Die Indizes sind natürlich case sensitive, also x.GetValue('A') ist etwas anderes als x.GetValue('a').

Count() und GetValueById() können verwendet werden, um alle Elemente der Zuordnungstabelle durchzugehen. Dies wäre dann mit einer For-Schleife möglich (In PHP würde man für diesen Zweck eine Foreach-Schleife verwenden).

Delphi-Quellcode:
var
  i: integer;
begin
  for i := 0 to List.Count - 1 do
  begin

  end;
end;
Diese Klasse müsste jedoch modifiert werden, wenn ihr Strings, Integer, Booleans oder Floats anstelle von Objekten verwalten wollt. Das wäre aber in sofern ungünstig, da dann viel rudundanter Code vorliegen würde. Ich habe mir jetzt von Java noch eine Interessante Funktionalität abgeguckt. Dort ist zwar der String ein abstrakter Datentyp, also eine Klasse, jedoch ist auch ein Integer bei Java ein einfacher Datentyp (int). Der Vorteil in Java: Weise ich ein int einem Object zu, wird dieser automatisch in eine Integer-Containerklasse gewandelt (toll!). In Delphi könnt ihr also folgende Helferklassen für meine Zuordnungsklasse verwenden:

Delphi-Quellcode:
type
  TString = class(TObject)
    Content: string;
  end;

  TInteger = class(TObject)
    Content: integer;
  end;

  TFloat = class(TObject)
    Content: float;
  end;

  TBoolean = class(TObject)
    Content: boolean;
  end;
Die Verwendung muss dann so aussehen:

Delphi-Quellcode:
MeinInteger := TInteger(x.GetValue('MeineZahl')).Content;
Wer natürlich ausschließlich mit Integers o.ä. arbeiten will, kann natürlich meinen Code editieren und alle TObject umwandeln. Verwaltet ihr aber Strings, müssen die Values mit UniqueString() speichertechnisch einzigartig gemacht werden:

Delphi-Quellcode:
procedure TEasyStringManager.SetValue(Name: string; Value: string);
var
  i: integer;
  n: TNameStringPair;
  found: boolean;
begin
  found := False;
  UniqueString(Value); // <-- Bei einer String-String Zuordnungstabelle ist diese Zeile zusätzlich nötig!
  for i := 0 to List.Count-1 do
  ...
Für Verbesserungsvorschläge bin ich natürlich immer offen!

Gruß
blackdrake

Dax 15. Mär 2009 20:54

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Das gibt es bereits, mit viel besserer Laufzeit: Hash-TabellenHash-Tabellen

Cyf 15. Mär 2009 21:42

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Delphi-Quellcode:
TStringList
Oder besser:

Zitat:

THashedStringList verwaltet eine Stringliste mit einer internen Hash-Tabelle.

Unit
IniFiles

Syntax


[Delphi] type THashedStringList = class (Classes.TStringList);


Beschreibung
Ein THashedStringList-Objekt ist eine Stringliste, die intern eine Hash-Tabelle verwendet, um die Suche nach Strings zu beschleunigen. Es wird intern von TMemIniFile verwendet, um die Strings in einer INI-Datei zu verwalten. Das Objekt kann jedoch wie jede andere Stringliste genutzt werden. Insbesondere bei Listen mit einer großen Anzahl von Strings kann die Leistung durch die Verwendung der Klasse THashedStringList anstelle von TStringList optimiert werden.

blackdrake 15. Mär 2009 21:44

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Hallo. Das mit den Hash-Tabellen schaue ich mir mal an und schaue, ob diese Klasse alles kann, was meine auch kann.

Aber TStringList kann doch die Funktionalität nicht wirklich ersetzen, oder? Eine TStringList ordnet Integer -> String/Object zu. Ich will aber String -> Object.

Cyf 15. Mär 2009 21:50

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Eine TStringList verwaltet Strings :roll: , optional kann man jedem ein Object hinzufügen.
Die Hashed-Variante ist in der Regel zu bevorzugen, jedoch nicht bei älteren Delphis verfügbar.

jaenicke 15. Mär 2009 22:55

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Zitat:

Zitat von blackdrake
Aber TStringList kann doch die Funktionalität nicht wirklich ersetzen, oder? Eine TStringList ordnet Integer -> String/Object zu. Ich will aber String -> Object.

Mit einer TStringList kann man nach Belieben standardmäßig Integer --> String (via Index), Integer --> Object (via Index), String --> Object (via IndexOf), String --> String (via Names).
Bei optimierter Implementierung kann aber eine eigene Klasse trotzdem sinnvoll sein. Dies ist eventuell das Interessante bei einer eigenen Implementierung. ;-)

Die Hashvariante oder eine andere Implementierung mit Hashes ist aber meistens noch besser, das ist sicher ebenfalls richtig.

Muetze1 16. Mär 2009 00:36

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
... und kann auch mit Strings als Index arbeiten, wenn man sich auf das Format Name=Wert einlässt. Aber wie die TStrings das intern handeln, kann einem ja egal sein.

Also - mal abgesehen von der THashStringList - klappt die String-Als-Index Sache von Haus aus mit TStringList. Siehe dazu [oh]TStrings.Values[][/oh].

alzaimar 16. Mär 2009 06:14

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Hier ist ein Performancevergleich verschiedener Suchalgorithmen, u.a. TStringList, THashedStringlist und Hashmaps.

blackdrake 16. Mär 2009 07:02

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Hallo.

Danke für eure Antworten.

Ich habe jetzt folgende Variante für TStringList und THashedStringList geschrieben. Dadurch wird der Code auch gleich viel schlanker.

Delphi-Quellcode:
uses
  IniFiles;

type
  TEasyObjectManager = class(TObject)
  published
    constructor Create(CaseSensitive: boolean);
    destructor Destroy; override;
  public
    function GetValue(Name: string): TObject;
    procedure SetValue(Name: string; Value: TObject);
    function ValueExists(Name: string): boolean;
    procedure DeleteValue(Name: string);
    function Count: integer;
    function GetValueById(Index: integer): TObject;
    function GetNameById(Index: integer): string;
  private
    List: THashedStringList; // Alternativ: TStringList
  end;

(*** TEasyObjectManager ***)

constructor TEasyObjectManager.Create(CaseSensitive: boolean);
begin
  inherited Create;
  List := THashedStringList.Create;
  // Ich bin der Meinung, man sollte das vorher definieren und nicht mittendrin ändern
  List.CaseSensitive := CaseSensitive;
end;

destructor TEasyObjectManager.Destroy;
begin
  if Assigned(List) then List.Free;
  inherited;
end;

function TEasyObjectManager.GetValue(Name: string): TObject;
var
  i: integer;
begin
  i := List.IndexOf(Name);
  if i <> -1 then
  begin
    result := List.Objects[i];
  end
  else
  begin
    result := nil;
  end;
end;

procedure TEasyObjectManager.SetValue(Name: string; Value: TObject);
var
  i: integer;
begin
  i := List.IndexOf(Name);
  if i <> -1 then
  begin
    List.Objects[i] := Value;
  end
  else
  begin
    UniqueString(Name); // Notwendig? 
    List.AddObject(Name, Value);
  end;
end;

function TEasyObjectManager.ValueExists(Name: string): boolean;
begin
  result := List.IndexOf(Name) <> -1;
end;

procedure TEasyObjectManager.DeleteValue(Name: string);
var
  i: integer;
begin
  i := List.IndexOf(Name);
  if i <> -1 then
  begin
    List.Delete(i);
  end;
end;

function TEasyObjectManager.Count: integer;
begin
  result := List.Count;
end;

function TEasyObjectManager.GetValueById(Index: integer): TObject;
begin
  result := List.Objects[Index];
end;

function TEasyObjectManager.GetNameById(Index: integer): string;
begin
  result := List.Strings[Index];
end;
Gruß
blackdrake

Cyf 16. Mär 2009 16:57

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Ok, das ist jetzt ein Wrapper für eine Klasse mit ein paar extra Methoden, um nicht jedesmal den Index mit den Funktionen dafür zu ermitteln, sondern das direkt da rein zu bauen? :gruebel: Wäre es nicht sinnvoller, wenn man die Klasse einfach ableitet und wenn man sowas braucht, das schnell hinzuzufügen, auch könnte das mit dem case sensitive sonst schwer werden?
Nebenbei sind auch die Abfragen, ob Einträge existieren unschön, entweder sie sollten dann angelegt werden, oder bei Abfragen sollte eine Exception geworfen werden, um zu signaliesieren, dass es den Eintrag nicht gibt, weil man nil ja auch zuweißen könnte.

Delphi-Quellcode:
// Ich bin der Meinung, man sollte das vorher definieren und nicht mittendrin ändern
Ich nicht, sowas sollte in eine Property.

blackdrake 17. Mär 2009 20:08

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Zitat:

Zitat von Cyf
Ok, das ist jetzt ein Wrapper für eine Klasse mit ein paar extra Methoden, um nicht jedesmal den Index mit den Funktionen dafür zu ermitteln, sondern das direkt da rein zu bauen? :gruebel:

Mh, hat zum einen damit zu tun, dass ich ursprünglich was eigenes gebaut hatte und die List-Möglichkeit nicht kannte, zum anderen dass ich meine Implementierung bei behalten will. Aber es hat auch was gutes: Wenn man mit dieser Wrapper-Klasse arbeitet, muss man sich nicht darum kümmern, wie die Liste eigentlich aufgebaut ist, sondern greift darauf zu wie eine INI-Datei.

Zitat:

Zitat von Cyf
Nebenbei sind auch die Abfragen, ob Einträge existieren unschön, entweder sie sollten dann angelegt werden, oder bei Abfragen sollte eine Exception geworfen werden, um zu signaliesieren, dass es den Eintrag nicht gibt, weil man nil ja auch zuweißen könnte.

In der Allgemeinen Lösung ja, aber ich brauche nur zu wissen, ob es nil ist oder nicht. nil oder nicht-vorhanden macht mir persönlich nichts aus.

Zitat:

Zitat von Cyf
Ich nicht, sowas sollte in eine Property.

Meiner Ansicht nach ist es schlecht, das Case-Sensitive mittendrin zu ändern. Dann gehen nämlich zum einen Einträge verloren, zum Anderen werden Einträge, die vorher existiert haben, plötzlich als nicht vorhanden gekennzeichnet. Ich bin der Meinung, das sollte man vorher exakt definieren. Ich muss ja im Allgemeinen beim Createn eines Objektes ja auch genau wissen, was ich denn erstellen will und kann mich dann auch nicht mehr umentscheiden.

Cyf 17. Mär 2009 22:07

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Zitat:

Zitat von blackdrake
Meiner Ansicht nach ist es schlecht, das Case-Sensitive mittendrin zu ändern. Dann gehen nämlich zum einen Einträge verloren, zum Anderen werden Einträge, die vorher existiert haben, plötzlich als nicht vorhanden gekennzeichnet. Ich bin der Meinung, das sollte man vorher exakt definieren. Ich muss ja im Allgemeinen beim Createn eines Objektes ja auch genau wissen, was ich denn erstellen will und kann mich dann auch nicht mehr umentscheiden.

Ich kann nicht nachvollziehen, warum Einträge verloren gehen sollen, natürlich werden kleingeschriebene Einträge dann nicht mehr mit einem großgeschriebenen Suchbegriff gefunden, aber das ist ja der Sinn der Sache und sollten weitere Anpassungen nötig sein, kannst du diese mit einer Methode hinter der Property durchführen. Der Sinn von Klasssen und OOP ist, sie so allgemein zu halten, dass sie wiederverwendbar sind und nicht nur für einen speziellen Anwendungsfall zu gebrauchen. Aber ist ja deine Klasse. :zwinker:
Aus dem selben Grund finde ich auch Ableiten hier geschickter als einen Wrapper: Man verliert nicht den Zugriff auf die alten Funktionen, sondern erreicht deine neuen nur zusätzlich und bleibt kompatibel zu Prozeduren, die die Vorfahren erwarten.

blackdrake 17. Mär 2009 22:14

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Zitat:

Zitat von Cyf
Ich kann nicht nachvollziehen, warum Einträge verloren gehen sollen

Ich hatte bei einem Test herausgefunden, dass wenn man z.B. "abc" zuweist, dann "ABC" zuweist, dann C.S. ausschaltet und dann auf "abc" zugreift, man eigentlich "ABC" erhält. Dieses Verschweißen der Einträge finde ich äußerst ungeschickt, denn das wäre wie wenn man Müll zuerst sortieren und dann in eine Tonne schütten würde, nur dass hier eben ein Verlust an Einträgen besteht. Ist das C.S. vorher definiert, kann explizit das Überschreiben und Neuanlegen durch die eigene Klasse kontrolliert werden. Deswegen habe ich lieber einen Wrapper gemacht als eine Ableitung.

Ja, im Allgemeinen Fall wäre eine Ableitung besser. Eben mit den einfachereren Funktionen als Zusatz.

Cyf 17. Mär 2009 22:24

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Das gleichlautende Einträge beim Abschalten kollidieren ist natürlich wahr, den Fall müsste man in der Tat berücksichtigen und überlegen, welcher in der Liste bleiben darf und ob dies ggf. irgendwie kenntlich gemacht wird (Exception, Message).

sx2008 18. Mär 2009 00:51

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Kennst du schon die Array-Properties?
Damit kann man die Sache sehr elegant lösen:
Delphi-Quellcode:
TEasyObjectManager = class(TObject)
private
  function GetValues(const Name: string): TObject;
  procedure SetValues(const Name: string; Value: TObject);
public
  ...
  // das ist ein Array-Property
  // interessant ist, das der Datentyp des Index auch string oder ein beliebiger anderer Datentyp sein darf
  // auch mehrdimensionale Indizes sind möglich
  property Values[const Name:string]:TObject read GetValues write SetValue;
end;
Ein bekanntes Array-Property ist z.B. Pixel[] der Klasse TCanvas.
Die Deklaration sieht ungefähr so aus:
Delphi-Quellcode:
property Pixel[x,y:Integer]:TColor read GetPixel write SetPixel;
Wenn man unsicher ist, wie die Get- und Set-Methoden aussehen sollen, dann schreibt
das Array-Property einfach hin und drückt dann Strg+Shift+C und die IDE erzeugt dann automatisch die richtigen Methodenkörper.

blackdrake 18. Mär 2009 06:57

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
:shock: Das ist ja was tolles! Vielen Dank für den Hinweis, da komm ich ja dem PHP-Fealing noch näher. Werde ich später gleich mal ausprobieren.

blackdrake 23. Mär 2009 10:17

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Hallo.

Ich bin jetzt zum entschluss gekommen, folgende Dinge zu machen:
1. Klasse von TStringList ableiten anstelle eines Wrappers
2. Exception werfen, wenn Eintrag nicht existiert anstelle nil zu liefern.

Bezüglich (1) möchte ich aber folgende Funktionweise: Es soll eine Exception geworfen werden, wenn durch das Ändern von Case-Sensitive Einträge miteinander "verschmelzen" (bzw. genau genommen danach nicht mehr durch ObjectByString[str] nicht mehr zugreifbar sind).

Dazu habe ich eine kleine Frage bevor ich meinen Code hier veröffentliche: Wie prüfe ich performant, ob bei einer CaseSensitive=False Änderung Einträge "verschmelzen" werden?

Gruß
blackdrake

blackdrake 27. Mär 2009 08:50

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Liste der Anhänge anzeigen (Anzahl: 1)
OK, hier nun mein fertiger Code:

Delphi-Quellcode:
unit ObjMan;

interface

uses
  SysUtils, IniFiles;

type
  TObjectManager = class(THashedStringList)
  private
    function GetObjectByString(const Str: String): TObject;
    procedure SetObjectByString(const Str: String; const Value: TObject);
    function GetStringByObject(const Obj: TObject): String;
    procedure SetStringByObject(const Obj: TObject; const Value: String);
  public
    function StringExists(const Str: String): boolean;
    function ObjectExists(const Obj: TObject): boolean;
    function DeleteString(const Str: String): boolean;
    property ObjectByString[const Str: string]: TObject
      read GetObjectByString write SetObjectByString;
    property StringByObject[const Obj: TObject]: String
      read GetStringByObject write SetStringByObject;
  end;

  EStringNotFound = class(Exception);
  EObjectNotFound = class(Exception);

resourcestring
  E_STRING_NOT_FOUND = 'The string "%s" was not found in the list.';
  E_OBJECT_NOT_FOUND = 'Object was not found in the list.';

implementation

{ TObjectManager } 

function TObjectManager.GetObjectByString(const Str: string): TObject;
var
  i: integer;
begin
  i := IndexOf(Str);
  if i <> -1 then
    result := Objects[i]
  else
    raise EStringNotFound.CreateFmt(E_STRING_NOT_FOUND, [Str]);
end;

procedure TObjectManager.SetObjectByString(const Str: string;
  const Value: TObject);
var
  i: integer;
begin
  i := IndexOf(Str);
  if i <> -1 then
    Objects[i] := Value
  else
    AddObject(Str, Value);
end;

function TObjectManager.StringExists(const Str: string): boolean;
begin
  result := IndexOf(Str) <> -1;
end;

function TObjectManager.ObjectExists(const Obj: TObject): boolean;
begin
  result := IndexOfObject(Obj) <> -1;
end;

function TObjectManager.DeleteString(const Str: string): boolean;
var
  i: integer;
begin
  i := IndexOf(Str);
  result := i <> -1;
  if result then Delete(i);
end;

function TObjectManager.GetStringByObject(const Obj: TObject): String;
var
  i: integer;
begin
  i := IndexOfObject(Obj);
  if i <> -1 then
    result := Strings[i]
  else
    raise EObjectNotFound.Create(E_OBJECT_NOT_FOUND);
end;

procedure TObjectManager.SetStringByObject(const Obj: TObject;
  const Value: String);
var
  i: integer;
begin
  i := IndexOfObject(Obj);
  if i <> -1 then
    Strings[i] := Value
  else
    AddObject(Value, Obj);
end;

end.
Die Exceptions bei "Verschmelzung" von Einträgen habe ich doch nicht gemacht, da ein solches Verhalten nicht nur durch Case-Sensitive entstehen kann, sondern auch, wenn man einfach zwei Einträge mit identischen Strings hinzufügt. Wenn man aber Konsequent nur mit ObjectByString[] arbeitet, kommt es zu keiner Überdeckung.

Man beachte bitte das dynamische Verhalten von SetStringByObject() und SetObjectByString(). Diese fügen einen neuen Eintrag hinzu, wenn man auf ein unbekanntes Element schreibend zugreift.

Gruß
blackdrake

himitsu 27. Mär 2009 10:11

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
ich spiel auch mal ein bissl mit :angel2: ... nja, zumindestens das "Array" funktioniert schonmal :stupid:
Delphi-Quellcode:
Uses Types, SysConst, SysUtils;

Type TMyType = Integer;
  TMyStringIndizeInnerArray = Array of Record
    Name: String;
    Data: TMyType;
  End;
  TMyStringIndizeArray = Record
  Private
    _A: TMyStringIndizeInnerArray;
    Procedure SetData(Const Name: String; Const Data: TMyType);
    Function GetData(Const Name: String):            TMyType;
    Procedure SetDataI(     Index: Integer; Const Data: TMyType);
    Function GetDataI(     Index: Integer):           TMyType;
    Function GetName (     Index: Integer):           String;
  Public
    Class Operator Implicit(Const A:  TMyStringIndizeInnerArray): TMyStringIndizeArray;
    Class Operator Implicit(Const Rec: TMyStringIndizeArray):     TMyStringIndizeInnerArray;
    Property Data[Const Name: String]: TMyType Read GetData Write SetData; Default;
    Property Data[      Index: Integer]: TMyType Read GetDataI Write SetDataI; Default;
    Property Name[      Index: Integer]: String Read GetName;
  End;

Procedure TMyStringIndizeArray.SetData(Const Name: String; Const Data: TMyType);
  Var i: Integer;

  Begin
    i := 0;
    While (i < Length(_A)) and (_A[i].Name <> Name) do Inc(i);
    If (i >= Length(_A)) Then Begin
      SetLength(_A, i + 1);
      _A[i].Name := Name;
    End;
    _A[i].Data := Data;
  End;

Function TMyStringIndizeArray.GetData(Const Name: String): TMyType;
  Var i: Integer;

  Begin
    i := High(_A);
    While _A[i].Name <> Name do Dec(i);
    Result := GetDataI(i);
  End;

Procedure TMyStringIndizeArray.SetDataI(Index: Integer; Const Data: TMyType);
  Begin
    If (Index >= 0) and (Index < Length(_A)) Then _A[Index].Data := Data
    Else Raise ERangeError.CreateRes(@SRangeError);
  End;

Function TMyStringIndizeArray.GetDataI(Index: Integer): TMyType;
  Begin
    If (Index >= 0) and (Index < Length(_A)) Then Result := _A[Index].Data
    Else Raise ERangeError.CreateRes(@SRangeError);
  End;

Function TMyStringIndizeArray.GetName(Index: Integer): String;
  Begin
    If (Index >= 0) and (Index < Length(_A)) Then Begin
      If _A[Index].Name <> '' Then Result := _A[Index].Name
      Else Result := IntToStr(Index);
    End Else Raise ERangeError.CreateRes(@SRangeError);
  End;

Class Operator TMyStringIndizeArray.Implicit(Const A: TMyStringIndizeInnerArray): TMyStringIndizeArray;
  Begin
    Result._A := A;
  End;

Class Operator TMyStringIndizeArray.Implicit(Const Rec: TMyStringIndizeArray): TMyStringIndizeInnerArray;
  Begin
    Result := Rec._A;
  End;


procedure TForm1.FormCreate(Sender: TObject);
Var A: TMyStringIndizeArray;

Begin
  //SetLength(A, 5);         // geht leider doch nicht ... blöder Var-Parameter -.-°
  A['himi'] := 0815;
  If A['himi'] = A[0] Then ;
  If Length(A) = 1    Then ; // aber warum geht das auch nicht? o.O
End;

jfheins 27. Mär 2009 11:08

Re: "Array" mit Strings als Indizes (Zuordnungstab
 
Sieht nett aus :thumb:

[OT]
Ich benutze in so einer Situation aber eher Dictionary<TKey, TValue> bzw. im speziellen dann Dictionary<String, int> :stupid:

SCNR :mrgreen:
[/OT]


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

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