Как определить последнюю итерацию в цикле по std:: map?

Я пытаюсь найти лучший способ определить, находится ли я в последней итерации цикла над картой, чтобы сделать что-то вроде следующего:

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 и т.д. Каков канонический метод?

Изменить: нет итераторов произвольного доступа для карт!

Ответ 1

Canonical? Я не могу этого требовать, но я предлагаю

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

Отредактировано, как было предложено KTC. (Спасибо! Иногда вы слишком быстро и беспорядочно по простейшим вещам...)

Ответ 2

Это кажется самым простым:

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

Ответ 3

Так как С++ 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
        }
    }

Хотя вопрос был задан некоторое время назад, я подумал, что стоит поделить.

Ответ 4

Если вы просто хотите использовать 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
        }
}

Ответ 5

Измененный маркер Ransom, поэтому он действительно работает по назначению.

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

Ответ 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
    }
}

Ответ 7

Следующий код будет оптимизирован компилятором, чтобы быть лучшим решением для этой задачи по производительности, а также по правилам ООП:

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

Это лучший код по правилам ООП, поскольку std:: map имеет специальную функцию-член rbegin для кода типа:

final_iter = someMap.end();
--final_iter;

Ответ 8

#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 действительно мал, вы можете использовать лямбда-функцию и избавиться от вызова в & Foo.

Ответ 9

Зачем работать, чтобы найти EOF, чтобы вы не что-то ему дали.

Просто исключить его

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

KISS (ХРАНИТЕ ЭТО ПРОСТО ПРОСТО)

Ответ 10

Простой, но эффективный подход:

  size_t items_remaining = someMap.size();

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

Ответ 11

Здесь мой оптимизированный подход:

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);

Ответ 12

Как насчет этого, никто не упоминает, но...

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

это кажется простым, мм...

Ответ 13

Полная программа:

#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

Ответ 14

Вы можете просто вытащить элемент из карты до итерации, а затем выполнить свою "последнюю итерацию" из цикла, а затем вернуть элемент обратно в карту. Это ужасно плохо для асинхронного кода, но, учитывая, насколько плохой остаток С++ для concurrency, я не думаю, что это будет проблемой.: -)