[yunqa.de] Re: Delphi structure ?

  • From: Delphi Inspiration <delphi@xxxxxxxx>
  • To: yunqa@xxxxxxxxxxxxx
  • Date: Thu, 14 Apr 2011 22:52:34 +0200

On 13.04.2011 17:39, Luc wrote:

> For a new project i need to implement a special structure In Delphi 
> which exists in Python.
> 
> Is there an equivalent structure in DIContainers for the python
> Dict(set) implementation.
> This is a structure which hashes to a uniqe key but the value consists
> of multiple sets.
> 
> example in python:
> 
> db=defaultdict(set)
> db[1,2].add('test1')
> db[1,2].add('test 2')
> db[1,2].add('test 3')
> print db
> 
> gives as result:
> 
> defaultdict(<type 'set'>, {(1, 2): set(['test1', 'test 2', 'test 3'])})
> 
> hask key (1,2) has multiple results as a set (test1,test2,test3)

I do not know Python, but a TDIHash container can be set up with one
type for the key and another type for the data. Both can be different
types, for example objects or records, and can contain multiple fields.

The TDIKeyHandler and TDIItemHandler instances which are passed to the
TDIHash constructor determine how the container handles its keys and
items, respectively:

constructor TDIHash.Create(
  const AItemHandler: TDIItemHandler;
  const AKeyHandler: TDIKeyHandler);

Below is a very simple console example to show how this may be
implemented in practice. Please modify according to your actual needs.

Ralf

//--------------------------------------------------------------------

{ Minimal demo for a TDIHash container with multiple key and item types. }
program Hash_Types;

{$APPTYPE Console}
{$I DI.inc}

uses
  {$IFDEF FastMM}FastMM4, {$ENDIF}SysUtils, DIContainers;

//--------------------------------------------------------------------

{ Define they key type and the TDIKeyHandler callback functions. }

type
  TKey = class
  public
    s1: string;
    s2: string;
  end;

  { Store the TKey object to the reserved memory. This moves the TKey
    to the TDIHash container. It will be freed by FreeKey_TKey below. }
procedure StoreKey_TKey(const PKeySource, PKeyDest: Pointer);
begin
  TKey(PKeyDest^) := TKey(PKeySource^);
end;

procedure FreeKey_TKey(const PKey: Pointer);
begin
  TKey(PKey^).Free;
end;

{ Calculate a simple hash value made up of two key fields. }
function HashKey_TKey(const PKey: Pointer): Cardinal;
begin
  with TKey(PKey^) do
    Result := HashKey_BufferCI(PChar(s1), Length(s1)) xor
      HashKey_BufferCI(PChar(s2), Length(s2));
end;

{ Compare two keys. Needed to resolve hash collisions. }
function SameKeys_TKey(const PKey1, PKey2: Pointer): Boolean;
begin
  Result :=
    (TKey(PKey1^).s1 = TKey(PKey2^).s1) and
    (TKey(PKey1^).s2 = TKey(PKey2^).s2);
end;

var
  KeyHandler: TDIKeyhandler = nil;

function GetKeyHandler: TDIKeyhandler;
begin
  if not Assigned(KeyHandler) then
    begin
      KeyHandler := TDIKeyhandler.Create;
      KeyHandler.KeySize := SizeOf(TKey);
      KeyHandler.OnStoreKey := StoreKey_TKey;
      KeyHandler.OnFreeKey := FreeKey_TKey;
      KeyHandler.OnHashKey := HashKey_TKey;
      KeyHandler.OnSameKeys := SameKeys_TKey;
    end;
  Result := KeyHandler;
end;

//--------------------------------------------------------------------

{ Define they key type and the TDIItemHandler callback functions. }

type
  TItem = class(TObject)
  public
    i1: string;
    i2: Integer;
    i3: Double;
  end;
  TItem_ptr = ^TItem;

procedure InitItem_TItem(const PItem: Pointer);
begin
  TItem(PItem^) := nil;
end;

procedure FreeItem_TItem(const PItem: Pointer);
begin
  TItem(PItem^).Free;
end;

var
  ItemHandler: TDIItemHandler = nil;

function GetItemHandler: TDIItemHandler;
begin
  if not Assigned(ItemHandler) then
    begin
      ItemHandler := TDIItemHandler.Create;
      ItemHandler.ItemSize := SizeOf(TItem);
      ItemHandler.OnInitItem := InitItem_TItem;
      ItemHandler.OnFreeItem := FreeItem_TItem;
    end;
  Result := ItemHandler;
end;

//--------------------------------------------------------------------

{ Small test of the above. }

const
  Count = 1000;
var
  i: Integer;
  Key: TKey;
  ItemPtr: TItem_ptr;
  Hash: TDIHash;
begin
  // Create Hash
  Hash := TDIHash.Create(GetItemHandler, GetKeyHandler);

  // Add Items

  for i := 0 to Count do
    begin
      { Create the key. This must be passed to Hash.InsertItemByKey()
        which takes an untyped parameter. }
      Key := TKey.Create;
      Key.s1 := IntToStr(i);
      Key.s2 := IntToStr(i);

      { Insert the key. This returns a pointer to the item. }
      ItemPtr := Hash.InsertItemByKey(Key);
      { Use the Item pointer to create the item and store data. }
      ItemPtr^ := TItem.Create;
      ItemPtr^.i1 := IntToStr(i);
      ItemPtr^.i2 := i;
      ItemPtr^.i3 := i;
    end;

  // Check Items

  Key := TKey.Create; // Temp key used for lookup.
  for i := 0 to Count do
    begin
      Key.s1 := IntToStr(i);
      Key.s2 := IntToStr(i);

      ItemPtr := Hash.PItemOfKey(Key);
      if not Assigned(ItemPtr) or (ItemPtr^.i2 <> i) then
        WriteLn('Error at ', i);
    end;
  Key.Free;

  // Free Hash. This frees the key and item instances.
  Hash.Free;

  KeyHandler.Free;
  ItemHandler.Free;

  WriteLn;
  WriteLn('Done - Press ENTER to Exit');
  ReadLn;
end.
_______________________________________________
Delphi Inspiration mailing list
yunqa@xxxxxxxxxxxxx
//www.freelists.org/list/yunqa



Other related posts: