29

我试图找出最好的方法来确定我是否处于地图上循环的最后一次迭代中,以便执行以下操作:

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
    }
}

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

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

4

15 回答 15

28

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

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

按照KTC的建议进行编辑以更正(谢谢!有时你走得太快,把最简单的事情搞砸了……)

于 2008-09-29T22:49:41.440 回答
23

从 C++11 开始,您还可以使用 std::next()

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

虽然这个问题是不久前提出的,但我认为值得分享。

于 2015-12-11T11:13:35.823 回答
14

这似乎是最简单的:

bool last_iteration = iter == (--someMap.end());
于 2008-09-29T22:47:19.857 回答
10

如果您只想使用 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
        }
}
于 2008-09-30T11:54:13.757 回答
6

修改了 Mark Ransom 的,所以它实际上按预期工作。

finalIter = someMap.end();
--finalIter;
if (iter != final_iter)
于 2008-09-29T22:57:57.367 回答
6

很惊讶没有人提到它,但当然 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
    }
}
于 2009-01-30T10:28:32.920 回答
3

以下代码将由编译器进行优化,以便在性能和 OOP 规则方面成为该任务的最佳解决方案:

if (&*it == &*someMap.rbegin()) {
    //the last iteration
}

这是 OOP 规则中最好的代码,因为 std::map 有一个特殊的成员函数 rbegin 用于如下代码:

final_iter = someMap.end();
--final_iter;
于 2011-12-08T12:47:57.817 回答
3

为什么要努力找到EOF,这样你就不会给它一些东西。

简单地说,排除它;

for (iter = someMap.begin(); someMap.end() - 1; ++iter) {
    //apply to all from begin to second last element
}

亲吻(保持简单)

于 2013-04-06T05:48:13.893 回答
1
#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 的调用。

于 2008-09-30T02:08:37.047 回答
1

这个怎么样,没有人说,但是...

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

这看起来很简单,嗯...

于 2015-11-02T10:34:30.807 回答
1

对于喜欢 C++11 基于范围的循环的人:

    for (const auto& pair : someMap) {
      if (&pair != &*someMap.rbegin()) ...
    }

注意只有引用类型在这里有效,而不是auto pair

于 2019-12-05T04:17:45.030 回答
0

一个简单但有效的方法:

  size_t items_remaining = someMap.size();

  for (iter = someMap.begin(); iter != someMap.end(); iter++) {
    bool last_iteration = items_remaining-- == 1;
  }
于 2008-09-29T23:01:10.057 回答
-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
于 2008-09-29T23:20:15.813 回答
-1

这是我的优化:

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);
于 2008-10-01T05:10:19.223 回答
-2

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

于 2008-09-29T22:47:57.453 回答