Как вы определяете последний действительный элемент в STL-контейнере - PullRequest
1 голос
/ 11 мая 2009

Если я перебираю контейнер STL, мне иногда нужно знать, является ли текущий элемент последним в последовательности. Есть ли лучший способ, чем делать что-то подобное? Могу ли я как-то конвертировать rbegin ()?

std::vector<int> myList;

// ....
std::vector<int>::iterator lastit = myList.end();  
lastit--;

for(std::vector<int>::iterator it = myList.begin(); it != myList.end(); it++)  {
     if(it == lastit)
     {
        // Do something with last element
     }
     else
     {
       //  Do something with all other elements
     }

Ответы [ 8 ]

3 голосов
/ 11 мая 2009

Попробуйте следующее

std::vector<int>::iterator it2 = (++it);
if ( it2 == myList.end() ) {
  ...
}

Следующее должно работать также

if ( it+1 == myList.end() ) {
  // it is last
  ...
}
2 голосов
/ 11 мая 2009

Может быть, вы можете выполнить итерацию в обратном направлении (используйте rbegin / rend) и поставить свое специальное задание перед циклом или заменить проверку конца на it != lastit и поставить специальную обработку после цикла

1 голос
/ 11 мая 2009

Используйте обратную итерацию , таким образом, у вас будет только одно end () - 1 -подобное вычисление (обратите внимание на rbegin () + 1) и без сравнений

for(vector<int>::iterator it = myValues.rbegin()+1; it != myValues.rend(); it++) {
    cout << *it << endl;
}
cout << "Process last one: " << *myValues.rbegin() << endl;

Также для вектора <> вычисление end () - 1, вероятно, быстрое, поэтому вы также можете сделать это следующим образом:

for(vector<int>::iterator it = myValues.begin(); it != myValues.end()-1; it++) {
    cout << *it << endl;
}
cout << "Process last one: " << *myValues.rbegin() << endl;

Если вы не хотите обрабатывать элемент после цикла, вы можете:

for(vector<int>::iterator it = myValues.rbegin(); it != myValues.rend(); it++) {
    if(it == myValues.rbegin())
        cout << "Process last one: " << *it << endl;
    else
        cout << *it << endl;
}
1 голос
/ 11 мая 2009

У меня были бы некоторые сомнения относительно моего дизайна, если бы некоторые элементы нужно обрабатывать по-разному, но это предложение немного чище для меня (не забудьте проверить пустые контейнеры)

std::vector<int>::iterator lastit = myList.end();
if (lastit != myList.begin())
{
  lastit--;
  for(std::vector<int>::iterator it = myList.begin(); it != lastit; ++it)
  {
     // Do
  }
  // Do with last
}
0 голосов
/ 10 ноября 2016

Почему бы и нет:

if(!myList.empty())
    last_it = myList.begin() + myList.size()-1;
else
    last_it = myList.end();


//or
    last_it = myList.empty() ? myList.end() : myList.begin() + myList.size() - 1;
0 голосов
/ 11 мая 2009

Важный вопрос: зачем создавать цикл, если вы делаете что-то особенное для 1 элемента. Почему бы не сделать что-то особенное для 3-го элемента? Каждому четвертому? ...

Просто переберите элементы, которые должны обрабатываться одинаково, напишите отдельный код для обработки остальных.

Посмотрите ответы на и на этот вопрос .

0 голосов
/ 11 мая 2009

Для итератора с произвольным доступом, такого как вектор, вам не нужен временный. Вы можете сказать:

if ( it + 1 == v.end() ) {
   // at one before end
}

Редактировать: И даже для не случайных типов доступа можно использовать std:; distance:

if ( distance( it, v.end() ) == 1 ) {
   // at one before end
}
0 голосов
/ 11 мая 2009

Если вы используете вектор, на самом деле намного проще использовать целочисленный индекс для итерации:

std::vector<int> myList;
for (unsigned int i = 0; i < myList.size(); i++)
{
  if (i == (myList.size() - 1))
  {
    processDifferently (myList[i])
  }
  else
  {
    process (myList[i])
  }
}

Минимизация количества вызовов myList.size () оставлена ​​в качестве упражнения для OP:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...