Difference between revisions of "User:Nhollm"
m (→TryAdd) |
|||
(22 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | {{Warning|All of this is subject to change. Do '''NOT''' use it until its finished. For any Questions or Input write me an E-Mail | + | {{Warning|All of this is subject to change. Do '''NOT''' use it until its finished. For any Questions or Input write me an E-Mail nhollm@gmx.de or write me at the forums 'nhollm'.}} |
− | |||
− | |||
==TDictionary== | ==TDictionary== | ||
− | TDictionary is a generic | + | TDictionary is a generic data-container for key-value pairs (associative array). <br> |
− | It was introduced with Generics.Collections in FPC 3. | + | It was introduced with Generics.Collections (rtl-generics) in FPC 3.1.1+. It's part of the FPC Runtime Library and fully Delphi compatible.<br> |
+ | (Like in Delphi) The TDictionary is implemented as a hash table. This means the key-value pairs are not sorted in a defined order. (= not iterable by index??)<br> | ||
+ | |||
+ | Both key and value can be of primitive type (e.g. integer, string, bool..) or rather complex (e.g. classes, records, arrays) | ||
==Basic syntax (FPC)== | ==Basic syntax (FPC)== | ||
Line 17: | Line 18: | ||
uses | uses | ||
− | Generics.Collections; | + | Generics.Collections; |
type | type | ||
− | TStrStrDictionary = specialize TDictionary<string, string>; | + | TStrStrDictionary = specialize TDictionary<string, string>; |
var | var | ||
Line 34: | Line 35: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | See also [[#Delphi]] syntax | ||
==Usage:== | ==Usage:== | ||
Line 41: | Line 44: | ||
===Add=== | ===Add=== | ||
− | Add | + | '''AddOrSetValue()''' is recommended, because '''Add()''' will fail, if the key already exists: 'Dublicate not allowed in Dictionary'.<br> |
+ | |||
+ | ====Add==== | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | MyDictionary.Add('Key1', 'Value1'); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ====AddOrSetValue==== | ||
+ | recommended | ||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
MyDictionary.AddOrSetValue('Key1', 'Value1'); | MyDictionary.AddOrSetValue('Key1', 'Value1'); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
===Remove=== | ===Remove=== | ||
Line 66: | Line 72: | ||
WriteLn(MyDictionary.Items['Key1']); | WriteLn(MyDictionary.Items['Key1']); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | If the provided key does not exist, this will throw an Error: 'Dictionary Key does not Exist'. You can use | + | If the provided key does not exist, this will throw an Error: 'Dictionary Key does not Exist'. You can use [[#TryGetValue|TryGetValue()]] instead. |
===Item Count=== | ===Item Count=== | ||
Total number of Items in dictionary (count) | Total number of Items in dictionary (count) | ||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
− | WriteLn('Items in Dictionary: ' | + | WriteLn('Items in Dictionary: ', IntToStr(MyDictionary.Count)); |
</syntaxhighlight> | </syntaxhighlight> | ||
===Loops=== | ===Loops=== | ||
+ | |||
+ | ====Loop Keys==== | ||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
− | |||
for KeyStr in MyDictionary.Keys do | for KeyStr in MyDictionary.Keys do | ||
− | WriteLn('Found key:' | + | WriteLn('Found key:', KeyStr); |
+ | </syntaxhighlight> | ||
− | + | ====Loop Values==== | |
− | + | <syntaxhighlight lang="pascal"> | |
for ValueStr in MyDictionary.Values do | for ValueStr in MyDictionary.Values do | ||
− | WriteLn('Found | + | WriteLn('Found value: ', ValueStr); |
+ | </syntaxhighlight> | ||
− | + | ====Loop Key-Value-Pairs==== | |
− | + | <syntaxhighlight lang="pascal"> | |
//var KeyValuePair : TStrStrDictionary.TDictionaryPair; | //var KeyValuePair : TStrStrDictionary.TDictionaryPair; | ||
for KeyValuePair in MyDictionary do | for KeyValuePair in MyDictionary do | ||
− | WriteLn('Found a Pair: Key:' | + | WriteLn('Found a Pair: Key:' , KeyValuePair.Key , ' Value:' , KeyValuePair.Value); |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 110: | Line 119: | ||
===Trying=== | ===Trying=== | ||
− | + | These functions return a boolean.<br> | |
− | True if sucessfull, False if not. No | + | True if sucessfull, False if not. No error is thrown, so they are a good alternative to [[#Get Value|Get Value]] or [[#Add|Add()]]. |
====TryAdd==== | ====TryAdd==== | ||
Line 120: | Line 129: | ||
writeln('not sucessfull'); | writeln('not sucessfull'); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | TryAdd does not update an existing keys value. Use AddOrSetValue instead. (Even tho there is no feedback provided) | + | Limitation: TryAdd does '''not''' update an existing keys value. Use [[#AddOrSetValue|AddOrSetValue()]] instead. (Even tho there is no feedback provided) |
+ | |||
====TryGetValue==== | ====TryGetValue==== | ||
TryGetValue takes two Arguments ->(key, value) and returns a boolean.<br> | TryGetValue takes two Arguments ->(key, value) and returns a boolean.<br> | ||
If found, it returns '''True''' and the provided 'value' variable becomes the value.<br> | If found, it returns '''True''' and the provided 'value' variable becomes the value.<br> | ||
− | If not found, the function returns '''False''' and the provided 'value'-variable is nil. | + | If not found, the function returns '''False''' and the provided 'value'-variable is '''nil'''. |
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
− | + | //var SearchedValue: string; | |
if MyDictionary.TryGetValue('Key', SearchedValue) then | if MyDictionary.TryGetValue('Key', SearchedValue) then | ||
WriteLn('Key found. Its value is: ' + SearchedValue) | WriteLn('Key found. Its value is: ' + SearchedValue) | ||
Line 198: | Line 208: | ||
try | try | ||
− | MyDictionary.AddOrSetValue('Key1', 'Value1');//triggers Add Event | + | MyDictionary.AddOrSetValue('Key1', 'Value1');//triggers 'Add' Event |
− | MyDictionary.AddOrSetValue('Key1', 'New Value');//triggers Add and Remove Event | + | MyDictionary.AddOrSetValue('Key1', 'New Value');//triggers 'Add' and 'Remove' Event |
− | MyDictionary.Remove('Key1');//triggers Remove Event | + | MyDictionary.Remove('Key1');//triggers 'Remove' Event |
readln(); | readln(); | ||
finally | finally | ||
Line 223: | Line 233: | ||
on E: Exception do begin | on E: Exception do begin | ||
− | WriteLn('An exception was raised: ' | + | WriteLn('An exception was raised: ', E.Message); |
WriteLn(E.ClassName); | WriteLn(E.ClassName); | ||
end; | end; |
Revision as of 10:50, 11 May 2024
Warning: All of this is subject to change. Do NOT use it until its finished. For any Questions or Input write me an E-Mail nhollm@gmx.de or write me at the forums 'nhollm'.
TDictionary
TDictionary is a generic data-container for key-value pairs (associative array).
It was introduced with Generics.Collections (rtl-generics) in FPC 3.1.1+. It's part of the FPC Runtime Library and fully Delphi compatible.
(Like in Delphi) The TDictionary is implemented as a hash table. This means the key-value pairs are not sorted in a defined order. (= not iterable by index??)
Both key and value can be of primitive type (e.g. integer, string, bool..) or rather complex (e.g. classes, records, arrays)
Basic syntax (FPC)
{$mode objfpc}
program Example;
uses
Generics.Collections;
type
TStrStrDictionary = specialize TDictionary<string, string>;
var
MyDictionary : TStrStrDictionary;
begin
MyDictionary := TStrStrDictionary.Create;
try
//do stuff with your dictionary..
finally
MyDictionary.Free;
end;
end.
See also #Delphi syntax
Usage:
Add
AddOrSetValue() is recommended, because Add() will fail, if the key already exists: 'Dublicate not allowed in Dictionary'.
Add
MyDictionary.Add('Key1', 'Value1');
AddOrSetValue
recommended
MyDictionary.AddOrSetValue('Key1', 'Value1');
Remove
MyDictionary.Remove('Key2');
If the Key does not exist, no Error is thrown.
Clear
MyDictionary.Clear;
Get Value
WriteLn(MyDictionary.Items['Key1']);
If the provided key does not exist, this will throw an Error: 'Dictionary Key does not Exist'. You can use TryGetValue() instead.
Item Count
Total number of Items in dictionary (count)
WriteLn('Items in Dictionary: ', IntToStr(MyDictionary.Count));
Loops
Loop Keys
for KeyStr in MyDictionary.Keys do
WriteLn('Found key:', KeyStr);
Loop Values
for ValueStr in MyDictionary.Values do
WriteLn('Found value: ', ValueStr);
Loop Key-Value-Pairs
//var KeyValuePair : TStrStrDictionary.TDictionaryPair;
for KeyValuePair in MyDictionary do
WriteLn('Found a Pair: Key:' , KeyValuePair.Key , ' Value:' , KeyValuePair.Value);
Check If Key/Value Exists
//Check if Key exists
if MyDictionary.ContainsKey('Key1') then
WriteLn('key exists')
else
WriteLn('key not found');
//Check if Value exists
if MyDictionary.ContainsValue('Searched value') then
writeln('value exists')
else
writeln('value not found');
Trying
These functions return a boolean.
True if sucessfull, False if not. No error is thrown, so they are a good alternative to Get Value or Add().
TryAdd
if MyDictionary.TryAdd('Key','TestValue') then
writeln('added successfully')
else
writeln('not sucessfull');
Limitation: TryAdd does not update an existing keys value. Use AddOrSetValue() instead. (Even tho there is no feedback provided)
TryGetValue
TryGetValue takes two Arguments ->(key, value) and returns a boolean.
If found, it returns True and the provided 'value' variable becomes the value.
If not found, the function returns False and the provided 'value'-variable is nil.
//var SearchedValue: string;
if MyDictionary.TryGetValue('Key', SearchedValue) then
WriteLn('Key found. Its value is: ' + SearchedValue)
else
WriteLn('Could not get value');
//writeln(BoolToStr(MyDictionary.TryGetValue('Key', SearchedValue), true));
ToArray
Returns an Array of type 'TDictionaryPair'.
//var myArray : array of TStrStrDictionary.TDictionaryPair;
myArray := MyDictionary.ToArray()
//WriteLn(length(myArray));
//WriteLn(myArray[0].Key)
//WriteLn(myArray[0].Value)
Event Notifications
You can set up custom Functions/Procedures which are triggered if an Key or Value got added/removed.
To do this, we add 2 procedures to the class we specialize from TDictionary.
The TDictionary class provides the in-build functions 'OnKeyNotify' and 'OnValueNotify'. Now we assign them to our procedures.
(Hint: If you update a existing value, there is no "updated"Event. Instead "removed" followed by "added" is triggered.)
TODO: get the Key Name inside the ValueNotify-Event kontext
{$mode objfpc}
program Example;
uses
Generics.Collections;
type
TStrStrDictionary = Class(Specialize TDictionary<String,String>)
private
procedure DoKeyNotify(ASender: TObject;constref AItem: ShortString; AAction: TCollectionNotification);
procedure DoValueNotify(ASender: TObject;constref AItem: ShortString; AAction: TCollectionNotification);
end;
procedure TStrStrDictionary.DoKeyNotify(ASender: TObject;constref AItem: ShortString; AAction: TCollectionNotification);
begin
//WriteLn(AAction);//AAction can be 'cnRemoved' or 'cnAdded'
if AAction = cnAdded then
writeln('A Key got added, the Key is:', AItem)
else if AAction = cnRemoved then
writeln('A Key got removed, the Key was:', AItem)
end;
procedure TStrStrDictionary.DoValueNotify(ASender: TObject;constref AItem: ShortString; AAction: TCollectionNotification);
begin
Writeln(AAction);//can be cnRemoved or cnAdded
if AAction = cnAdded then
writeln('A Value got added, the value is:', AItem)
else if AAction = cnRemoved then
writeln('A Value got removed, the value was:', AItem)
end;
var
MyDictionary : TStrStrDictionary;
TestArr : array of TStrStrDictionary.TDictionaryPair;
begin
MyDictionary := TStrStrDictionary.Create;
//Event notifications:
MyDictionary.OnKeyNotify:=@MyDictionary.DoKeyNotify;
MyDictionary.OnValueNotify:=@MyDictionary.DoValueNotify;
try
MyDictionary.AddOrSetValue('Key1', 'Value1');//triggers 'Add' Event
MyDictionary.AddOrSetValue('Key1', 'New Value');//triggers 'Add' and 'Remove' Event
MyDictionary.Remove('Key1');//triggers 'Remove' Event
readln();
finally
MyDictionary.Free;
end;
end.
Exceptions
To handle Exceptions, import the SysUtils Library.
{$mode objfpc}
program Example;
...
uses
... SysUtils;
try
WriteLn(MyDictionary.Items['KeyXY']); // Accessing a non-existing key
except
on E: Exception do begin
WriteLn('An exception was raised: ', E.Message);
WriteLn(E.ClassName);
end;
end;
//Output:
// An exception was raised: Dictionary key does not exist
//EListError
Delphi
{$mode delphi}
uses generics.collections;
type TStrIntDict = TDictionary<string,integer>;
var
MyDict : TStrIntDict;
begin
MyDict:=TStrIntDict.create;
MyDict.AddorSetValue('foo',42);
if MyDict.ContainsKey('foo') then
WriteLn(MyDict['foo']);
end.