* * *

Author Topic: associative arrays in lazarus?  (Read 8401 times)

ustak

  • New member
  • *
  • Posts: 5
associative arrays in lazarus?
« on: February 14, 2007, 08:21:54 pm »
Hi!
My problem is:
Can I use associative and! multidimensional arrays in lazarus? Is there any component of it?
I'd like to do somethig like this:
Myarray["peter",1]:=10;
Myarray["peter",2]:=20;
Myarray["joe",1]:=4;
etc...

Myarray:array of string of array of integer
Is it possible?

Thanks for your answer!
Good work to you!

Ustak.

Zink

  • New member
  • *
  • Posts: 15
RE: associative arrays in lazarus?
« Reply #1 on: February 18, 2007, 10:13:12 pm »
I'm afraid not. If string keys can be constant (defined at compile time) you can do like this:

var
 my_array_keys: (peter, michael, anna, joe);
 my_array: array[peter..joe] of array of Integer;

begin
 my_array[anna,2]:= 10;

In that case keys must be unique in whole unit (compiles treats them as global constants).

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3165
RE: associative arrays in lazarus?
« Reply #2 on: February 18, 2007, 10:22:37 pm »
Another solution is to simply use a database to manage the data. I like sqlite. There are several dozens of other databases available out there.

tlacuache

  • New member
  • *
  • Posts: 14
    • http://grovers.us/seth
RE: associative arrays in lazarus?
« Reply #3 on: February 19, 2007, 08:30:24 pm »
On the freepascal.org "contributed units" page, under miscellaneous (http://www.freepascal.org/contrib/db.php3?category=Miscellaneous), search for "Associative arrays". This seems to do what you want (I have not used it, so I cannot give you a guarantee).

You can download the unit(s) from there, or it links to http://4programmers.net/Delphi/Artyku%C5%82y/Tablice_asocjacyjne which is not in English but which seems to have some examples of use as well.

-SG

tlacuache

  • New member
  • *
  • Posts: 14
    • http://grovers.us/seth
RE: associative arrays in lazarus?
« Reply #4 on: February 19, 2007, 08:32:17 pm »
Actually, I'm sorry, the download link on the pages I just mentioned seem to be broken.

-SG

zzarr

  • New member
  • *
  • Posts: 5
RE: associative arrays in lazarus?
« Reply #5 on: January 17, 2008, 08:13:10 am »
Hi!

I also want associative arrays. I remember that I made a class in Delphi 6 to handle associative arrays (only strings).

Please, don't be angry if this doesn't work, I'm writing it from my memory.

Code: [Select]


type

  TAssocArray = class
    FElements: array of string; {You can change this to whatever type you want}
    FIndexList: TStrings;
  public
    constructor Create;
    destructor Destroy;
    function GetValue(index: string): string;
    procedure SetValue(index,value: string);
    property Items[index: string] read GetValue write SetValue; default; // must be public, it can't be published (it's an array property)
  end;

implementation

constructor TAssocArray.Create;
begin
  FIndexList := TStringList.Create;
end;

destructor TAssocArray.Destroy;
begin
  FIndexList.Free;
end;

function TAssocArray.GetValue(index: string): string;
var
  i: integer;
begin
  i := FIndexList.IndexOf(index);
  if i >= 0 then GetValue := FElements[i] else GetValue := '';
end;

procedure TAssocArray.SetValue(index,value: string);
var
  i,len: integer;
begin
  i := FIndexList.IndexOf(index);
  if i = -1 then
  begin
    len := length(FElements);
    SetLength(FElements,len+1);
    FElements[len] := value;
    FIndexList.Add(index);
  end else
  begin
    FElements[i] := value;
  end;
end;



I hope this work, I'm not sure.

note: it might be possible to change "string" to "object" in the array to make it possible to add other values than strings.

Greetings
zzarr

Troodon

  • Sr. Member
  • ****
  • Posts: 485
Associative array (hash) in Lazarus = TStringHashList
« Reply #6 on: November 08, 2008, 08:45:40 pm »
The type you are looking for is TStringHashList, in unit StringHashList, but documentation is somewhat difficult to read. Below is the definition; the link to the complete doc is: http://lazarus-ccr.sourceforge.net/docs/lcl/stringhashlist/tstringhashlist.html

Code: [Select]
type TStringHashList = class(TObject)
protected
  function HashOf();
  procedure Insert();
public
  constructor Create();
  destructor Destroy; override;
  function Add();
  procedure Clear;
  function Find();
  function Remove();
  property CaseSensitive: Boolean; [rw]
  property Count: Integer; [r]
  property Data: Pointer; default; [rw]
  property List: PStringHashItemList; [r]
end;


The TStringHashList documentation indicates that the value in the key-value pair must be of type Pointer, which is a useful generalization as it allows to store any data type in the hash.

So let's say you want to create a hash of TPoint. Open a new project in Lazarus, add a button Button1 and a memo Memo1 to your form, and an onClick event handler method to your button as follows:

Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, StringHashList;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
    SH: TStringHashList;
  end;

var
  Form1: TForm1;
  i: Integer;


implementation

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  aPoint: ^TPoint;
begin
  // initialize hash
  SH := TStringHashList.Create(False);
  // insert a few TPoint elements into hash
  for i := 0 to 3 do begin
    New(aPoint);
    aPoint^.X := i;
    aPoint^.Y := i;
    SH.Add(IntToStr(i), aPoint);
  end;
  // copy hash key-value pair info to memo text
  for i := 0 to (SH.Count - 1) do begin
    Memo1.Lines.Add(SH.List[i]^.Key + ' => (' +
      IntToStr(TPoint(SH.List[i]^.Data^).X) + ', ' +
      IntToStr(TPoint(SH.List[i]^.Data^).Y) + ')'
    );
  end;
  // delete hash
  SH.Destroy;  // also disposes of ^TPoint data
end;

initialization
  {$I unit1.lrs}

end.


Run the program, click Button1 and you will see in the Memo1 text area this:

Code: [Select]
0 => (0, 0)
1 => (1, 1)
2 => (2, 2)
3 => (3, 3)


Notice that, to add a new key-value pair to the hash, a pointer to TPoint is created. To store simpler data types in values, e. g., a String or an Integer, you need to create dynamic variables (pointers) that hold that data. For example, to add a key-value pair where the key is 'a' and the value is 'b' you would use NewStr('b'). The TStringHashList.Destroy destructor disposes of all pointers created in the process.

The value can be a pointer to an array of type TMyArray; then you would probably retrieve element j in the array like this:

  myDataItem := TMyArray(MyList.List^.Data^)[j]

To summarize:

a) create MyList of type TStringHashList using the Create constructor
b) add key-value pairs to the hash using MyList.Add(<key>, <value>) where <key> is a string and <value> is a dynamic variable (=pointer)
c) retrieve key-value pair data using MyList.List^.Key and typecasting MyList.List^.Data^ to the data type you have stored in the list  -- where i := 0 to (MyList.Count - 1)
d) destroy the TStringHashList using the Destroy destructor

Now, I have a question: Regarding the TStringHashList.Destroy destructor, it is unclear to me whether Destroy is implicitly called when a TStringHashList object is part of a higher level dynamic data structure that is being resized. For example, let MyDataSet: array of TStringHashList; upon calling SetLength(MyDataSet, x), is TStringHashList.Destroy automatically called for the deleted array elements?
Lazarus/FPC on Linux

Troodon

  • Sr. Member
  • ****
  • Posts: 485
Re: associative arrays in lazarus?
« Reply #7 on: March 07, 2009, 04:26:09 am »
This is the first time I have actually had a closer look at the StringHashList unit (lazarus/lcl/stringhashlist.pas) and I am totally confused as to how one of the data structures is declared and manipulated.

Consider the PStringHashItemList data type in this unit:

Code: [Select]
type
  PStringHashItem = ^TStringHashItem;
  TStringHashItem = record
    HashValue: Cardinal;
    Key: String;
    Data: Pointer;
  end;

  PStringHashItemList = ^PStringHashItem;

  TStringHashList = class(TObject)
  private
    FList: PStringHashItemList;
    ....
  end;

As you can I see, PStringHashItemList is a pointer to a pointer to a record. But further below, in the TStringHashList.Add method, there is this peculiar (to me) statement:

Code: [Select]
Case CompareValue(Val, FList[I]^.HashValue)<=0 of
Here, FList looks like some kind of dynamic array of pointer, yet that is not how it was declared. And then, in the TStringHashList.Insert method FList is accessed by its index again:

Code: [Select]
FList[Index] := Item;
Obviously, it works, so Markus (the author) must have done something right. But I can't help wondering: what kind of data type is that? I am familiar with linked lists and dynamic arrays but how pointer data can be addressed by index without typecasting beats me. Even if the entire set of TStringHashItem were somehow kept adjacent in the heap (by using ReallocMem and System.Move at item insertion time?) I still find it hard to understand how the index thing works.

BTW, the code above doesn't compile in Delphi. Anyone could please explain how this is done in Lazarus?
« Last Edit: March 07, 2009, 05:47:51 am by Troodon »
Lazarus/FPC on Linux

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2626
    • My Lazarus wiki user page
Re: associative arrays in lazarus?
« Reply #8 on: March 07, 2009, 10:19:38 am »
From the fpc docs:
Quote
Free Pascal treats pointers much the same way as C does. This means that a pointer to some type can be treated as being an array of this type.
For more information, see the fpc docs.

Troodon

  • Sr. Member
  • ****
  • Posts: 485
Re: associative arrays in lazarus?
« Reply #9 on: March 07, 2009, 03:08:34 pm »
Free Pascal treats pointers much the same way as C does. This means that a pointer to some type can be treated as being an array of this type.

That explains it. Thanks.
Lazarus/FPC on Linux

vexal

  • New member
  • *
  • Posts: 29
Re: associative arrays in lazarus?
« Reply #10 on: August 08, 2011, 03:15:38 pm »
Just a few years later... I was looking for associatives arrays and i found this topic so maybe this will be useful for someone else.
Associative array can be implemented this way : http://fbeaulieu.developpez.com/guide/miniprojet/#LIV
Code and explainations are in French but can be easily translated via online translation tool
The class can be dowloaded here : http://fbeaulieu.developpez.com/guide/miniprojet/05_tableaux_associatifs.zip

Example :
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  TA: TableauAssociatif;
begin
  TA := TableauAssociatif.Create;
  TA['prénom'] := 'Jacques';
  TA['nom'] := 'Dupont';
  TA['age'] := '53';
  ShowMessage(TA['prénom'] + ' ' + TA['nom'] + ' a ' + TA['age'] + ' ans.');
  TA.Destroy;
end;

Leledumbo

  • Hero Member
  • *****
  • Posts: 2997
Re: associative arrays in lazarus?
« Reply #11 on: August 09, 2011, 06:34:35 am »
Don't make it complicated, it's easy:
Code: [Select]
uses
  fgl;
...
type
  TValueArray = array of Integer;
  TNameValueMap = specialize TFPGMap<String,TValueArray>;
...
var
  NameValueMap: TNameValueMap;
begin
  NameValueMap := TNameValueMap.Create;
  SetLength(NameValueMap['peter'],10);
  NameValueMap['peter',1] := 10;
  NameValueMap['peter',2] := 20;
  SetLength(NameValueMap['joe'],10);
  NameValueMap['joe',1] := 4;
end;
just change TValueArray if you want static arrays

eny

  • Hero Member
  • *****
  • Posts: 813
Re: associative arrays in lazarus?
« Reply #12 on: August 09, 2011, 09:50:40 pm »
Don't make it complicated, it's easy:
Code: [Select]
  SetLength(NameValueMap['peter'],10);
This doesn't seem to work (at least not with my config).
WinXP Prof SP3; Lazarus 0.9.30; FPC 2.4.4; 2011-06-02 (#29749)

Leledumbo

  • Hero Member
  • *****
  • Posts: 2997
Re: associative arrays in lazarus?
« Reply #13 on: August 10, 2011, 01:43:50 am »
Quote
This doesn't seem to work (at least not with my config).
Sorry, it was untested code and I forgot about property and var parameter. Fixed code (standalone program):
Code: [Select]
{$mode objfpc}{$H+}
uses
  fgl;

type
  TValueArray = array of Integer;
  TNameValueMap = specialize TFPGMap<String,TValueArray>;
var
  NameValueMap: TNameValueMap;
  TempValueArray: TValueArray;
begin
  NameValueMap := TNameValueMap.Create;

  TempValueArray := NameValueMap['peter'];
  SetLength(TempValueArray,10);
  TempValueArray[1] := 10;
  TempValueArray[2] := 20;
  NameValueMap['peter'] := TempValueArray;

  TempValueArray := NameValueMap['joe'];
  SetLength(TempValueArray,10);
  TempValueArray[1] := 4;
  NameValueMap['joe'] := TempValueArray;
end.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1189
Re: associative arrays in lazarus?
« Reply #14 on: September 15, 2011, 09:55:52 pm »
My problem is:
Can I use associative and! multidimensional arrays in lazarus? Is there any component of it?

No, since associative arrays are horribly limited.

Use a tstringlist of whatever subarray type you like.
 

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads