微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Delphi字典和订购数据

我的代码是:

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中获得不同的价值?
为什么值不按添加顺序存储?

我是Delphi的菜鸟,不知道Dictionary是如何运作的.我在谷歌没有找到任何相关信息.
你能解释一下为什么会这样吗?
有没有办法使用词典而不使用TList<>对于排序数据?

谢谢

解决方法

字典不维护元素的顺序,因为它在内部组织为查找表的方式,并且由键的哈希值排序.它们针对速度进行了优化,而不是为了保持订购.

如果您需要维护元素的顺序,则需要配对列表而不是字典.德尔福没有提供开箱即用的功能.您可以使用以下代码实现简单的配对列表,并根据您的需要对其进行自定义.

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,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;

然后你可以像使用字典一样使用它,但是会保持元素的顺序.

var
  Pairs: TPairs<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;

对于较新的Delphi版本的SetValue更新,其中在TList< T>中没有FItems.后裔班.

procedure TPairs<TKey,TValue>;
begin
  i := IndexOfKey(Key);
  if i >= 0 then
    begin
      Pair := Items[i];
      Pair.Value := Value;
      Items[i] := Pair;
    end
  else
    begin
      Pair.Create(Key,Value);
      inherited Add(Pair);
    end;
end;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐