2011-02-18 4 views
2

私はデータを格納するためにDelphi 6でDeCALのDMultiMapコンテナを使用しています。キーはマップ内に数回現れる文字列です。DelphiでDMultiMap(DeCAL)の検索結果を適切に反復処理する方法は?

特定のキーを持つすべてのオブジェクトに対して正しく反復処理する方法を知りました。

ウィルこのコード:

function IterateOverObjects(map: DMultimap); 
var iter: DIterator; 
begin 
    iter := map.locate(['abc']); 
    while IterateOver(iter) do 
    begin 
    // do something with the value... 
    end; 
end; 

リターンキーとして 'ABC' とのすべてのオブジェクト?または、最初のオブジェクトからマップのすべてのオブジェクトを 'abc'をキーとして返しますか?

編集:テスト済みです。 'abc'をキーとして最初のオブジェクトからマップのすべてのオブジェクトを返します。 'abc'を反復処理する最良の方法は何ですか?

答えて

1

EDIT:テストバージョン(私はそれを見つけ、高速使用していないことを調べたので、私は、以前に使用findifを変更した、それだけですべてのアイテムをループ):

EDIT2:私の前回のテストが悪かったので、私はそれが適切に機能するように編集しました。 Nameの答えとほぼ同じですが、誤った機能を持つ人を混乱させないように変更しました。

function IterateOverFound(Map: DMultiMap; var iter: DIterator; const obj: array of const): Boolean; 
begin 
    if diIteration in iter.flags then 
    begin 
    advance(iter); 
    SetToKey(iter); 
    iter := findIn(iter, Map.finish, obj); 
    end 
    else 
    begin 
    iter := Map.locate(obj); 
    Include(iter.flags, diIteration); 
    end; 

    Result := not atEnd(iter); 
    if not result then 
    Exclude(iter.flags, diIteration); 
end; 

使用例:

var 
    iter: DIterator; 

    iter := map.start; 
    while IterateOverFound(map, iter, ['abc']) do 
    begin 
    SetToValue(iter); 
    // get value 
    end; 
+0

ありがとうございます。私は構文が好きです。しかし2つの問題:それは同じアイテムに無期限にとどまり、SetToKeyの呼び出しがありません。あなたの投稿に関数の修正版を追加しましたが、それはピアレビュー後にのみ表示されます。 – Name

+0

@名前:修正されたバージョンを別の回答として投稿する必要があります。 – jalf

+0

私の回答を編集しました – Linas

1

私はいくつかの研究を行い、1つの解決策を見つけました。 DMultiMap次のコードが動作するように(黒ツリー上ではなく、ハッシュ値に基づく)順序付きマップは、同じキーを持つすべての項目がグループ化されているとおり

function IterateOverObjects(map: DMultimap); 
var iter1, iter2: DIterator; 
begin 
    iter1 := map.locate(['abc']); 
    if not AtEnd(iter1) then 
    begin 
    iter2 := map.upper_bound(['abc']); 
    repeat 
     // do something with the value... 
     Advance(iter1); 
    until equals(iter1, iter2); 
    end; 
end; 

別の可能性は次のようになります

function IterateOverObjects(map: DMultimap); 
var iter: DIterator; 
begin 
    iter := map.locate(['abc']); 
    while IterateOver(iter) do 
    begin 
    SetToKey(iter); 
    if (getString(iter) <> 'abc') then break; 
    SetToValue(iter); 
    // do something with the value... 
    end; 
end; 
1

私はリナによって提案された使用例の構文は好きですが、機能が正常に動作しないよう、ここでは修正バージョンです。 FindInが速く見つけ使用していないという事実、唯一の反復処理に使用されているように、問題ではありません(同じキーを持つすべてのアイテムが一緒になるようにDMultiMapは、注文したマップである):

function IterateOverFound(Map: DMultiMap; var iter: DIterator; const obj: array of const): Boolean; 
var bWasToKey: boolean; 
begin 
    if diIteration in iter.flags then 
    begin 
    advance(iter); 
    bWasToKey := diKey in iter.flags; 
    SetToKey(iter); 
    iter := DeCAL.findIn(iter, DeCAL.getContainer(iter).finish, obj); 
    if not bWasToKey then 
     SetToValue(iter); 
    end else 
    begin 
    iter := Map.locate(obj); 
    Include(iter.flags, diIteration); 
    end; 
    result := not atEnd(iter); 
    if not result then 
    Exclude(iter.flags, diIteration); 
end; 

使用例:

var 
    map: DMultiMap; 
    iter: DIterator; 

map := DMultiMap.Create; 
map.putPair(['aaa', 0]); 
map.putPair(['def', 1]); 
map.putPair(['abc', 2]); 
map.putPair(['abc', 3]); 
map.putPair(['def', 4]); 
map.putPair(['abc', 5]); 
map.putPair(['def', 6]); 
iter := map.start; 
while IterateOverFound(map, iter, ['abc']) do 
begin 
    // do something with the value... 
end; 
+1

このバージョンは問題ありません。私のテストケースは、以前はbasでした:)一つのこと:あなたはパラメータとしてmapを持っているので、findinでgetContainer(iter)を呼び出す必要はありません。 – Linas

+0

getContainerを呼び出す必要がないことについての良い点。 – Name