Как определить последнюю итерацию в цикле по 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, я не думаю, что это будет проблемой.: -)