2015-08-27 69 views
3

我的代碼是:德爾福字典和訂貨數據

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的noob,不知道字典是如何工作的。我在Google中沒有找到任何關於此的信息。 你能解釋一下爲什麼這樣嗎?
有沒有任何方法可以使用字典,而不使用TList <>用於排序數據?因爲它的方式是內部組織爲查找表,它是由密鑰的散列有序

感謝

回答

3

字典不維護元素的順序。它們針對速度進行了優化,而不是保持排序。

如果您需要維護元素的順序,您需要配對列表而不是字典。 Delphi不提供這種開箱即用的功能。您可以使用以下代碼來實現簡單的對列表並根據您的需要對其進行自定義。

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; 

然後你可以像使用字典一樣使用它,但元素的順序將被保留。

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; 

SetValue較新版本的Delphi其中FItemsTList<T>子孫類可用的更新。

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 
    begin 
     Pair := Items[i]; 
     Pair.Value := Value; 
     Items[i] := Pair; 
    end 
    else 
    begin 
     Pair.Create(Key, Value); 
     inherited Add(Pair); 
    end; 
end; 
+0

非常感謝! – Marusyk

+0

未標記的條目 左側不能被分配到 過程TPairs .SetValue(Key:TKey; const Value:TValue); var i:整數; 對:TPair ; begin i:= IndexOfKey(Key); if i> = 0 then FItems [i] .Value:= Value << == build, else begin Pair.Create(Key,Value); 繼承添加(Pair); 結束; 結束; –

+0

@MetaMussel在較新的Delphi版本中不再可訪問FItems。我爲這些添加了更新。 –