如何在std :: map的循环中检测到最后一次迭代?

时间:2020-03-06 14:54:02  来源:igfitidea点击:

我正在尝试找出确定自己是否在地图循环的最后迭代中的最佳方法,以便执行以下操作:

for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
    bool last_iteration;
    // do something for all iterations
    if (!last_iteration) {
        // do something for all but the last iteration
    }
}

似乎有几种方法可以做到这一点:随机访问迭代器,"距离"函数等。规范方法是什么?

编辑:没有用于地图的随机访问迭代器!

解决方案

这似乎是最简单的:

bool last_iteration = iter == (--someMap.end());

我们可以仅在迭代之前将元素从地图中拉出,然后从循环中执行"最后一次迭代"工作,然后将元素放回地图中。对于异步代码来说,这是非常糟糕的,但是考虑到其余C ++对于并发的严重性,我认为这不会成为问题。 :-)

典范?我不能这么说,但我建议

final_iter = someMap.end();
--final_iter;
if (iter != final_iter) ...

根据KTC的建议进行编辑以更正。 (谢谢!有时我们走得太快,弄乱了最简单的事情……)

修改了Mark Ransom,使其实际上按预期工作。

finalIter = someMap.end();
--finalIter;
if (iter != final_iter)

一种简单但有效的方法:

size_t items_remaining = someMap.size();

  for (iter = someMap.begin(); iter != someMap.end(); iter++) {
    bool last_iteration = items_remaining-- == 1;
  }

完整程序:

#include <iostream>
#include <list>

void process(int ii)
{
   std::cout << " " << ii;
}

int main(void)
{
   std::list<int> ll;

   ll.push_back(1);
   ll.push_back(2);
   ll.push_back(3);
   ll.push_back(4);
   ll.push_back(5);
   ll.push_back(6);

   std::list<int>::iterator iter = ll.begin();
   if (iter != ll.end())
   {
      std::list<int>::iterator lastIter = iter;
      ++ iter;
      while (iter != ll.end())
      {
         process(*lastIter);
         lastIter = iter;
         ++ iter;
      }
      // todo: think if you need to process *lastIter
      std::cout << " | last:";
      process(*lastIter);
   }

   std::cout << std::endl;

   return 0;
}

该程序产生:

1 2 3 4 5 | last: 6

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <algorithm>

using namespace boost::lambda;

// call the function foo on each element but the last...
if( !someMap.empty() )
{
  std::for_each( someMap.begin(), --someMap.end(), bind( &Foo, _1 ) );
}

使用std :: for_each将确保循环紧密且准确...请注意引入了带有单个参数的foo()函数(类型应与someMap所包含的匹配)。这种方法增加了1行。当然,如果Foo很小,则可以使用lambda函数并摆脱对&Foo的调用。

如果我们只想使用ForwardIterator,则应该可以使用:

for ( i = c.begin(); i != c.end(); ) {
        iterator cur = i++;
        // do something, using cur
        if ( i != c.end() ) {
                // do something using cur for all but the last iteration
        }
}

这是我的最佳选择:

iter = someMap.begin();

do {
    // Note that curr = iter++ may involve up to three copy operations
    curr = iter;

    // Do stuff with curr

    if (++iter == someMap.end()) {
        // Oh, this was the last iteration
        break;
    }

    // Do more stuff with curr

} while (true);

还没有人感到惊讶,但是boost当然有一些特色;)

Boost.Next(和等效的Boost.Prior)

示例如下所示:

for (iter = someMap.begin(); iter != someMap.end(); ++iter) {
    // do something for all iterations
    if (boost::next(iter) != someMap.end()) {
        // do something for all but the last iteration
    }
}