Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi extract key from TObjectDictionary

sharing the code on this question as reference: Delphi TPair Exception

How can I retrieve the key and value from a TObjectDictionary concrete entry without using TPair and without extracting/remove/delete the pair from the list ?

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Generics.Defaults,
  Generics.Collections;

type
  TProduct = class
  private
    FName: string;
    procedure SetName(const Value: string);
  published
  public
    property Name: string read FName write SetName;
  end;

type
  TListOfProducts = TObjectDictionary<TProduct, Integer>;

{ TProduct }

procedure TProduct.SetName(const Value: string);
begin
  FName := Value;
end;


var
  MyDict: TListOfProducts;
  MyProduct1: TProduct;
  MyProduct2: TProduct;
  MyProduct3: TProduct;
  APair: TPair<TProduct, Integer>;
  aKey: string;

begin
  try
    MyDict := TListOfProducts.Create([doOwnsKeys]);
    MyProduct1 := TProduct.Create;
    MyProduct1.Name := 'P1';
    MyProduct2 := TProduct.Create;
    MyProduct2.Name := 'P2';
    MyProduct3 := TProduct.Create;
    MyProduct3.Name := 'P3';

    MyDict.Add(MyProduct1, 1);
    MyDict.Add(MyProduct2, 2);
    MyDict.Add(MyProduct3, 3);

    //the code to look for a **concrete product** (ie: MyProduct1) goes here..

    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Thanks.

=========================

= Code with the answer =

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Generics.Defaults,
  Generics.Collections;

type
  TProduct = class
  private
    FName: string;
    procedure SetName(const Value: string);
  published
  public
    property Name: string read FName write SetName;
  end;

type
  TListOfProducts = TObjectDictionary<TProduct, Integer>;

{ TProduct }

procedure TProduct.SetName(const Value: string);
begin
  FName := Value;
end;


var
  MyDict: TListOfProducts;
  MyProduct1: TProduct;
  MyProduct2: TProduct;
  MyProduct3: TProduct;

  MySearchedProduct: TProduct;   // From Answer.

  APair: TPair<TProduct, Integer>;
  aProductName: string;

begin
  try
    MyDict := TListOfProducts.Create([doOwnsKeys]);
    MyProduct1 := TProduct.Create;
    MyProduct1.Name := 'P1';
    MyProduct2 := TProduct.Create;
    MyProduct2.Name := 'P2';
    MyProduct3 := TProduct.Create;
    MyProduct3.Name := 'P3';

    MyDict.Add(MyProduct1, 1);
    MyDict.Add(MyProduct2, 2);
    MyDict.Add(MyProduct3, 3);

    Writeln('Enter the Product Name to search: ');

    //the code to look for a **concrete product** goes here..
    Readln(aProductName);
    for MySearchedProduct in Mydict.Keys do
      if (MySearchedProduct.Name = aProductName) then
        break;
    if MySearchedProduct.Name = aProductName then
      WriteLn('I have found the product: ' + MySearchedProduct.Name)
    else
      WriteLn('I have not found a product with that name.');

    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
like image 657
ferpega Avatar asked May 03 '11 07:05

ferpega


3 Answers

You can use The Keys and Values properties of MyDict.

In a loop like this:

var
  MyProduct: TProduct;
  Value: Integer;
begin

  for Value in MyDict.Values do
    writeln(Value);

  for MyProduct in MyDict.Keys do
    writeln(MyProduct.Name);

Or by index using ToArray:

writeln(MyDict.Keys.ToArray[1].Name);
writeln(MyDict.Values.ToArray[1]);
like image 104
Mikael Eriksson Avatar answered Nov 04 '22 11:11

Mikael Eriksson


The Key and Value are saved in the dictionary as a TPair<TKey,TValue>. If you need to work with both key and value, the logical thing to do is use a TPair;

Looks like this:

for APair in MyDict do
begin
  // Your stuff goes here.
end;

If for some reason you don't want to use TPair to extract the pairs you may use something like this, but this is absolutely not a good idea - you're doing lots of dictionary queries for no good reason:

for AKey in MyDict.Keys do
begin
  AValue := MyDict[AKey];
  // Do something with both AKey and AValue
end;
like image 41
Cosmin Prund Avatar answered Nov 04 '22 09:11

Cosmin Prund


Looping through the keys could be extrimely slow if your dictionary contains lots of members. I suggest keeping the key in the Pair along with the real value. Considering the example provided it might look like this:

type
 TListOfProducts = TObjectDictionary<TProduct, TPair<TProduct,Integer>>;
like image 40
dvfedorov Avatar answered Nov 04 '22 11:11

dvfedorov