德尔福字典和订购数据 [英] Delphi Dictionary and ordering data
问题描述
我的代码是:
procedure TfrmSettings.btnFillDictClick(Sender: TObject);
var
Dict: TDictionary<string, string>;
Item: TPair<string, string>;
begin
Dict := TDictionary<string, string>.Create();
Dict.Add('Key1', 'Text1');
Dict.Add('Key2', 'Text2');
Dict.Add('Key3', 'Text3');
Dict.Add('Key4', 'Text4');
for Item in Dict do
begin
ShowMessage(Item.Key + ' ' + Item.Value);
end;
end;
为什么几乎每次我在Showmessage中获得不同的价值?
为什么值不按照添加顺序存储?
Why almost every time I'm getting a different value in Showmessage?
Why values are not stored in the order in which they were added?
我是Delphi中的一个noob,不知道Dictionary如何工作。而且我没有在Google上找到有关这方面的信息。
可以请你解释一下为什么会这样吗?
有没有办法使用Dictionary而不使用TList<>进行排序数据?
I'm a noob in Delphi and do not know how Dictionary is working. And I didn't find any information about this in Google.
Could you please explain me why it is so?
Is there any way to use Dictionary without using TList<> for sort data?
谢谢
推荐答案
字典不保留元素的顺序,因为它的内部组织方式是查找表,它被排序通过键的哈希。它们针对速度进行了优化,不保留订购。
Dictionary does not maintain order of elements because the way it is internally organized as look up table and it is ordered by the hash of the key. They are optimized for speed and not to preserve ordering.
如果您需要维护元素的顺序,您需要配对列表而不是字典。 Delphi没有提供开箱即用。您可以使用以下代码实现简单的对列表,并根据您的需要进行自定义。
If you need to maintain order of elements you need pair list instead of dictionary. Delphi does not provide that out of the box. You can use following code to implement simple pair list and customize it for your needs.
type
TPairs<TKey, TValue> = class(TList < TPair < TKey, TValue >> )
protected
fKeyComparer: IComparer<TKey>;
fValueComparer: IComparer<TValue>;
function GetValue(Key: TKey): TValue;
procedure SetValue(Key: TKey; const Value: TValue);
function ComparePair(const Left, Right: TPair<TKey, TValue>): Integer;
public
constructor Create; overload;
procedure Add(const aKey: TKey; const aValue: TValue); overload;
function IndexOfKey(const aKey: TKey): Integer;
function ContainsKey(const aKey: TKey): Boolean; inline;
property Values[Key: TKey]: TValue read GetValue write SetValue;
end;
constructor TPairs<TKey, TValue>.Create;
begin
if fKeyComparer = nil then fKeyComparer := TComparer<TKey>.Default;
if fValueComparer = nil then fValueComparer := TComparer<TValue>.Default;
inherited Create(TDelegatedComparer <TPair<TKey, TValue>>.Create(ComparePair));
end;
function TPairs<TKey, TValue>.ComparePair(const Left, Right: TPair<TKey, TValue>): Integer;
begin
Result := fKeyComparer.Compare(Left.Key, Right.Key);
if Result = 0 then Result := fValueComparer.Compare(Left.Value, Right.Value);
end;
function TPairs<TKey, TValue>.IndexOfKey(const aKey: TKey): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to Count - 1 do
if fKeyComparer.Compare(Items[i].Key, aKey) = 0 then
begin
Result := i;
break;
end;
end;
function TPairs<TKey, TValue>.ContainsKey(const aKey: TKey): Boolean;
begin
Result := IndexOfKey(aKey) >= 0;
end;
function TPairs<TKey, TValue>.GetValue(Key: TKey): TValue;
var
i: Integer;
begin
i := IndexOfKey(Key);
if i >= 0 then Result := Items[i].Value
else Result := default (TValue);
end;
procedure TPairs<TKey, TValue>.SetValue(Key: TKey; const Value: TValue);
var
i: Integer;
Pair: TPair<TKey, TValue>;
begin
i := IndexOfKey(Key);
if i >= 0 then FItems[i].Value := Value
else
begin
Pair.Create(Key, Value);
inherited Add(Pair);
end;
end;
procedure TPairs<TKey, TValue>.Add(const aKey: TKey; const aValue: TValue);
begin
SetValue(aKey, aValue);
end;
然后,您可以使用与使用字典相同的方式,但会维护元素的顺序
And then you can use it the same way you would use dictionary, but order of elements will be maintained.
var
Pairs: TPairs<string, string>;
Item: TPair<string, string>;
begin
Pairs := TPairs<string, string>.Create();
Pairs.Add('Key1', 'Text1');
Pairs.Add('Key2', 'Text2');
Pairs.Add('Key3', 'Text3');
Pairs.Add('Key4', 'Text4');
Pairs.Add('Key5', 'Text5');
for Item in Pairs do
begin
Memo1.Lines.Add(Item.Key + ' ' + Item.Value);
end;
end;
这篇关于德尔福字典和订购数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!