开发者

How to iterate properly over the search results of a DMultiMap (DeCAL) in Delphi?

开发者 https://www.devze.com 2023-02-11 15:49 出处:网络
I am using the DMultiMap container from DeCAL with Delphi 6 to store data. The key is a string which can appears several time in the map.

I am using the DMultiMap container from DeCAL with Delphi 6 to store data. The key is a string which can appears several time in the map.

I wonder how to iterate properly over all objects with a given key.

Will this code:

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

returns all the objects of with 'abc' as key? Or will it returns all the objects of the map starting from the first object with 'abc' as key?

Edit: Just tested. It returns all the objects of the map starting from the first object with 'abc' as key. What is then the best way to iterate over 'abc'?


EDIT: tested version (I've changed previously used findif, because I investigated that it doesn't use fast locate, it just loops through all the items):

EDIT2: because my previous test was bad, I've edited function to make it work properly. it looks almost the same as Name's answer, but I changed it to not confuse anyone with incorrect function.

    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;

Example usage:

var
  iter: DIterator;

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


In the meanwhile I made some researches and found one solution. As DMultiMap is an ordered map (based on a black tree and not on an hash value), all items with the same key are grouped so that following code works:

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;

Another possibility would be:

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;


I like the syntax of the usage example proposed by Linas, but as the function doesn't work properly, here is a corrected version. The fact that FindIn doesn't use a fast locate isn't a problem, as it is only used to iterate (A DMultiMap is an ordered map, so that all items with the same key are together):

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;

Example usage:

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

精彩评论

暂无评论...
验证码 换一张
取 消