2011-09-07 35 views
5

我使用的是C++ std::multimap,我必须遍历两个不同的键。有没有一种有效的方式来做到这一点,而不是创建两个范围并单独循环这些范围?std :: multimap获取两个范围

这是即时通讯的方式做现在:

std::pair<std::multimap<String, Object*>::iterator,std::multimap<String, Object*>::iterator> range; 
std::pair<std::multimap<String, Object*>::iterator,std::multimap<String, Object*>::iterator> range2; 

// get the range of String key 
range = multimap.equal_range(key1); 
range2 = multimap.equal_range(key2); 

for (std::multimap<String, Object*>::iterator it = range.first; it != range.second; ++it) 
{ 
    ... 
} 
for (std::multimap<String, Object*>::iterator it2 = range2.first; it2 != range2.second; ++it2) 
{ 
    ... 
} 
+2

你为什么觉得效率不高? –

+0

这是我第一次使用multimap,所以我不太熟悉它们。我会在这些循环中做很多工作,我想知道是否有另一种操作可以在同一时间或两者之间获得两个范围。 –

+0

你可以给出一个钥匙重叠的例子,但不相等吗?也许我的大脑是湿漉漉的,但它似乎是一个简单的平等检查的关键会做到这一点。对于每个查询,如果您有单独的上限和下限,对我来说更有意义。 –

回答

3

您开始使用的代码是最直接的。

如果您确实想在同一个循环中迭代两个范围,您可以创建一个自定义迭代器,该迭代器需要两个迭代器范围,迭代第一个范围,直到完成,然后切换到第二个迭代器范围。这可能比它的价值更麻烦,因为你需要自己实现所有的迭代器成员。

编辑:我正在反思这个;只需将两个循环修改为一个循环就很简单。

for (std::multimap<String, Object*>::iterator it = range.first; it != range2.second; ++it) 
{ 
    if (it == range.second) 
    { 
     it = range2.first; 
     if (it == range2.second) 
      break; 
    } 
    ... 
} 
+0

我想到了这一点。但是,这两个键必须彼此相邻才能工作?例如,如果我有3个键,我想循环第一和第三不会包含第二个与他们?或者做那些如果陈述修复? –

+1

@Kaiser,'if'语句处理从第一个范围到第二个范围的转换。他们甚至可能失灵。他们*不能做的唯一事情就是相交;如果'range2'包含'range.second',那么你会得到一个无限循环。 –

+0

啊,我明白了。我的范围2是静态的,范围1总是会有所不同。他们不应该相交正确?由于multimap在插入时对它进行排序? –

3

当然,Boost会这样做。使用Boost.Range和它的join函数会得到你想要的。有关更多详细信息,请参见Boost Range Library: Traversing Two Ranges Sequentially

+0

谢谢,Boost似乎真的很强大。不幸的是,我的公司是老派,不喜欢新的东西......我猜他们必须要解决效率低下问题 –

+0

这不是关于效率,而是关于便利性 –

0

如果你有机会到C++ - 11(Visual Studio的10+,GCC-4.5 +),并允许使用它auto是一个真正的宝石:

// get the range of String key 
auto range = multimap.equal_range(key1); 
auto range2 = multimap.equal_range(key2); 

for (auto it = range.first; it != range.second; ++it) 
{ 
    ... 
} 
for (auto it2 = range2.first; it2 != range2.second; ++it2) 
{ 
    ... 
} 

无论如何,我只想测试键只有在key2!= key1的情况下才执行第二个循环。每次在循环中检查迭代器都会产生一定的代价。

来自第二个范围的std :: set_difference可能简化代码。 也许std :: set_union这两个范围,并通过back_inserter插入到一个集,所以你只能得到一个副本?

一些实验可能是有序的。不要忘记在混音中加入你的第一个猜测。在速度方面,它可能会让你感到惊讶。除非范围通常非常长,并且/或者循环操作昂贵,否则可能不值得额外记账。