19

TEnumerator を使用して TDictionary をキー順に並べ替えるにはどうすればよいですか?

私はこのようなものを持っています:

  var
    Dic: TDictionary<string, string>;
    Enum: TPair<string, string>;

  begin
    Dic := TDictionary<string, string>.create;
    Dic.Add('Tired', 'I have been working on this too long');
    Dic.Add('Early', 'It is too early in the morning to be working on this');
    Dic.Add('HelpMe', 'I need some help'); 
    Dic.Add('Dumb', 'Yes I know this example is dumb');

   { I want to do the following but do it in sorted order by Enum.Key }
    for Enum in Dic do
      some processing with Enum.Key and Enum.Value;

    Dic.Free;
  end;

したがって、辞書を次の順序で処理したいと思います: ダム、アーリー、ヘルプミー、タイテッド。

残念ながら、Delphi のヘルプでは、一般的な列挙子と TEnumerator が具体的にどのように機能するかについての説明が非常に少なく、私が見つけることができる例はありません。また、Delphi でジェネリックを使用して列挙子を使用する方法については、ウェブ上でほとんど書かれていません。

また、上記のサンプル コードは TEnumerator を使用していないため、これがどのように使用されるように設計されているかについて混乱しています。


バリー、答えてくれてありがとう。

質問をしてからのジェネリックへの冒険は興味深いものでした。私は自分のコードにそれらを実装したいと思っていました。ジェネリックにはソートを処理するメソッドが組み込まれているように見えるため、「ソート」の問題はやや困惑していましたが、それを行う方法に関する良い例やドキュメントはありません。

最後に、Barry が提案したことを実行し、外部インデックスを Dictionary に組み込みました。それでも、それは正しくありません。

ただし、別の驚きがありました。 Gabr の GPStringHash を Generic の TDictionary に置き換えようとしてです。コードは、ジェネリックによって少しきれいになりました。しかし、結論としては、TDictionary は Gabr の 3 倍以上遅いということでした。TryGetValue への 1,704,667 回の呼び出しには 0.45 秒かかりましたが、Gabr のルーチンに対する同じ操作には 0.12 秒かかりました。理由はわかりませんが、Gabr がより高速なハッシュ関数とバケットの組み合わせを持っているのと同じくらい単純かもしれません。あるいは、すべてのケースに対してジェネリックを一般化する必要があり、それが本質的に速度を低下させているのかもしれません。

それでも、Barry や他の Delphi 開発者はこれを検討する必要があります。個人的には、選択肢があれば、サードパーティのパッケージ (Gabr と同じくらい良いものでも) よりも、言語に組み込まれているものを使用する方が早いでしょう。しかし、今のところ、GPStringHash に固執します。

4

3 に答える 3

21

ディクショナリはハッシュテーブルであるため、アイテムをソートされた順序で格納しません。TEnumeratorは単純です。これは、アイテムを反復処理するための手段にすぎません。

アイテムを順番に取得するには、アイテムを並べ替える必要があります。1つの方法は、次のように、それらをリストに入れてリストを並べ替えることです。

var
  list: TList<string>;
begin
  list := TList<string>.Create(Dic.Keys);
  try
    list.Sort;
    // process sorted list of items now
  finally
    list.Free;
  end;
end;
于 2010-03-27T06:43:18.397 に答える
7

私の場合、TDictionary < String, String > を使用します。TKeyCollectionクラス。

function compareKey(const L, R: String): Integer;
begin
  Result := SysUtils.CompareText(L, R);
end;

function getReverseSortedKeyArray(dictionary: TDictionary<String, String): TArray<String>;
var
  keyArray: TArray<String>;
  keyCollection: TDictionary<String, String>.TKeyCollection;
begin
  keyCollection:= TDictionary<String, String>.TKeyCollection.Create(dictionary);
  try
    keyArray:= keyCollection.ToArray;
    TArray.Sort<String>(keyArray, TComparer<String>.Construct(compareKey));
  finally
    keyCollection.Free;
  end;

  Result := keyArray;
end;

使用例:

var
  key: String;
  keyArray : TArray<String>;
begin
    keyArray  := getSortedKeyArray (dictionary);
    for key in keyArray  do
    begin
      // ...
    end;
end;
于 2013-04-11T07:23:46.423 に答える
5

Array<T>またはを介し​​てソートするサンプル コードを次に示しTList<T>ます。キーと値のペアの関係が保持され、キーの代わりに値でソートするように調整することもできます。また、匿名メソッドを使用して並べ替えを行います。

句には必ず and を含めGenerics.CollectionsGenerics.Defaultsください。usesを使用して並べ替える最初の方法TArray<T>:

procedure TestSortDictionaryViaArray;
var
  D: TDictionary<string, Integer>;
  A: TArray<TPair<string, Integer>>;
  P: TPair<string, Integer>;
begin
  D := TDictionary<string, Integer>.Create;

  D.Add('Test - 6', 6);
  D.Add('Test - 1', 1);
  D.Add('Test - 0', 0);
  D.Add('Test - 4', 4);
  D.Add('Test - 3', 3);
  D.Add('Test - 5', 0);
  D.Add('Test - 2', 2);

  A := D.ToArray;

  TArray.Sort<TPair<string, Integer>>(A,
    TComparer<TPair<string, Integer>>.Construct(
      function (const L, R: TPair<string, Integer>): Integer
      begin
        Result := CompareStr(L.Key, R.Key);
      end)
  );

  for P in A do
    ShowMessage(P.Key);
  D.Free;
end;

そして、これは使用していTList<T>ます:

procedure TestSortDictionaryViaList;
var
  D: TDictionary<string, Integer>;
  L: TList<TPair<string, Integer>>;
  P: TPair<string, Integer>;
begin
  D := TDictionary<string, Integer>.Create;

  D.Add('Test - 6', 6);
  D.Add('Test - 1', 1);
  D.Add('Test - 0', 0);
  D.Add('Test - 4', 4);
  D.Add('Test - 3', 3);
  D.Add('Test - 5', 0);
  D.Add('Test - 2', 2);

  L := TList<TPair<string, Integer>>.Create(D);

  L.Sort(
    TComparer<TPair<string, Integer>>.Construct(
      function (const L, R: TPair<string, Integer>): Integer
      begin
        Result := CompareStr(L.Key, R.Key);
      end)
  );

  for P in L do
    ShowMessage(P.Key);

  D.Free;
  L.Free;
end;

追加の (および不必要な) 情報:TList<T>メソッドではリストを解放する必要がありますが、では解放TArray<T>する必要はありません。内部的には、TList<T>使用しますTArray<T>(たとえば、TArrayクラスBinarySearch()メソッドをTList<T>持ち、BinarySearch メソッドを持ちます)。

于 2013-04-18T09:42:22.053 に答える