2

我正在使用 DeCAL 中的 DMultiMap 容器Delphi 6 来存储数据。键是一个可以在地图中出现多次的字符串。

我想知道如何使用给定键正确迭代所有对象。

将这段代码:

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”的最佳方法是什么?

4

3 回答 3

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;
于 2011-02-18T11:32:09.910 回答
1

编辑:测试版本(我改变了以前使用的 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;
于 2011-02-18T11:45:28.137 回答
1

我喜欢 Linas 提出的用法示例的语法,但由于该函数无法正常工作,这里有一个更正的版本。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;
于 2011-02-21T09:00:57.323 回答