【问题标题】:How to use BOOST_FOREACH with two std::maps?如何将 BOOST_FOREACH 与两个 std::maps 一起使用?
【发布时间】:2009-04-20 20:03:03
【问题描述】:

我的代码基本上是这样的:

std::map<int, int> map1, map2;
BOOST_FOREACH(int i, map1)
{
    // do steps 1-5 here...
}
BOOST_FOREACH(int i, map2)
{
    // do steps 1-5 (identical to above) here...
}

有没有办法连接地图以消除第二个循环中的重复代码?或者一种扩展 BOOST_FOREACH 以一次性遍历两个不同地图的方法?显然我不想增加程序的时间复杂度(否则我可以创建一个新地图并将其插入 map1 和 map2)。我有一种感觉,我在这里遗漏了一些基本的东西。

【问题讨论】:

  • 您是否故意迭代 int?你应该使用 pair 而不仅仅是 int。还是 boost 最近获得了仅对值进行迭代的可能性?
  • 如果有的话,我希望这样的功能只能迭代密钥......但它也不适用于我的 Boost 版本。

标签: c++ stl boost foreach maps


【解决方案1】:

你可以定义一个函数:

typedef std::map<int, int> IntMap;

void doStuffWithInt(IntMap::value_type &i)
{
  // steps 1 to 5
}

BOOST_FOREACH(IntMap::value_type &i, map1)
  doStuffWithInt(i);
BOOST_FOREACH(IntMap::value_type &i, map2)
  doStuffWithInt(i);

虽然在这种情况下使用std::for_each 可能会更简单:

for_each(map1.begin(), map1.end(), doStuffWithInt);
for_each(map2.begin(), map2.end(), doStuffWithInt);

【讨论】:

  • 如果您将整数映射到整数(std::map),我相信迭代器将指向 std::pair 而不是普通整数?
  • 是的,我可能并没有注意到这一点——不过不要混淆这个问题,修复起来应该不会太难
【解决方案2】:

这里的想法是编写一种特殊类型的迭代器来虚拟合并两个容器,就 BOOST_FOREACH 而言。请注意,我不是从现有的两个容器中创建新容器。我只是从第一个容器的 end() 跳转到第二个容器的 begin() 迭代器。 我没有尝试编写实际的merged_iterator 类,但是虽然写起来可能有点长,但在技术上并不困难。我真的很惊讶没有使用谷歌找到类似的东西。不过我没找多久!

template<typename Container>
boost::iterator_range<
  merged_iterator<Container::iterator>
  >
concat_containers( Container& c1, Container& c2 )
{
  typedef merged_iterator<typename Container::iterator> MergedIterator;
  typedef boost::iterator_range<MergedIterator> IteratorRange;
  return IteratorRange(
    MergeIterator( c1.begin(), c1.end(), c2.begin(), c2.end() ),
    MergeIterator( c2.end(), c1.end(), c2.begin(), c2.end() ) );
}

// Now use a bit of magic to define merged_iterator<...>
// And you'll be able to write

BOOST_FOREACH( std::pair<int, int> i, concat_containers( map1, map2 ) )
{
// Do whatever you want here
}

【讨论】:

  • 我几天前为了另一个问题实现了它。请注意,它尚未得到证实,可能需要进行一些调整:stackoverflow.com/questions/757153/…
  • +1 用于提供非常通用的方法,例如甚至可以跨不同的容器类型工作。但我觉得这对于手头的问题可能是过度设计的——只需制作一个像 0800 INFORMATION 建议的功能! :)
  • 对于这个特定的问题来说,这太过分了。我只是想我可以尝试并玩得开心:)
【解决方案3】:

除了我推荐的 1800 的解决方案之外,还有各种 hacky 解决方案:

for (int stage = 0; stage < 2; stage++) {
    BOOST_FOREACH(int i, stage == 0 ? map1 : map2) {
        ...
    }
}

typedef std::map<int, int> intmap;
std::vector<intmap *> v;
v.push_back(&map1);
v.push_back(&map2);
BOOST_FOREACH(intmap *m, v) {
    BOOST_FOREACH(int i, *m) {
        ...
    }
}

注意:当我看到同事写这样的代码时,有时我会被一种无法抗拒的想要扼杀他们的冲动所征服。使用风险自负。

【讨论】:

  • 附注+1:您必须始终考虑得到什么,失去什么。如果您只是获得了代码的压缩并且您失去了可读性,那么它不会补偿。
  • 我也投了赞成票,因为我喜欢你的两种方式。第一个是相当紧凑和可读的。第二个也是。尽管我会将其更改为读取 intmap* v[] = { &map1, &map2 }; BOOST_FOREACH(intmap *m, v) { ... } 。我认为在这种情况下“原始”数组很好。
【解决方案4】:

最简单的方法是这样的:

std::map<int, int> map1, map2;
int key, value;
BOOST_FOREACH(boost::tie(key, value), boost::join(map1, map2))
{
    // do steps 1-5 here...
}

不用担心这些逗号不会因为括号而混淆预处理器。

【讨论】:

    【解决方案5】:

    我想试试

    std::map<int, int> map1, map2;
    std::map<int, int>& maps = { map1, map2 }
    BOOST_FOREACH(std::map<int, int> map, maps)
      BOOST_FOREACH(int i, map)
      {
          // do steps 1-5 here...
      }
    

    【讨论】:

      【解决方案6】:

      解释了here

      你可以这样做:

      std::map<int,int> m;
      typedef std::pair<int,int> pair_t;
      BOOST_FOREACH(pair_t p, m)
      

      【讨论】:

        猜你喜欢
        • 2010-10-22
        • 1970-01-01
        • 2010-12-20
        • 1970-01-01
        • 1970-01-01
        • 2017-03-27
        • 2015-03-06
        • 2011-07-09
        • 2020-12-13
        相关资源
        最近更新 更多