Проверьте, является ли элемент первым или последним в std :: vector

У меня есть следующее for each кода C++:

for (auto item : myVector)
{
    std::cout << item;

    if (item == orderBy.IsLast())       // <--- Check if this is the last element
        std::cout << "(Is last element) " << std::endl;
    else if (item == orderBy.IsFirst()) // <-- Check if this is the first element
        std::cout << "(Is first element)" << std::endl;
}

Конечно, IfLast() и IfFirst() не существуют в std::vector. Есть ли собственный std:: way для проверки первого и последнего элемента?

Ответы

Ответ 1

В этом случае вы не должны использовать for на основе диапазона, так как этот тип for "скрывает" итератор, и вам понадобится дополнительный счетчик для отслеживания положения в векторе. Вы можете просто сделать

for(auto it = myVector.begin(); it != myVector.end(); ++it)
{
    if(it == myVector.begin()) // first element
    {
        // do something
    }
    else if(std::next(it) == myVector.end()) // last element
    {
        // do something else
    }
}

Обратите внимание, что простое сравнение my.Vector.back() с вашим элементом из диапазона основано на ОК, только если вы уверены, что у вас нет дубликатов в векторе. Но если, например, значение последнего элемента появляется несколько раз в векторе, вы найдете только его первую позицию. Итак, почему нет хорошего способа использования for на основе диапазона без дополнительного индекса, который отслеживает, где именно находится вектор.

РЕДАКТИРОВАТЬ См. также @thelink2012 ответ на вопрос о том, как "обмануть" ваш for на основе диапазона, чтобы вы могли нести позицию элемента неявно.

Ответ 2

Используйте std::vector::front и std::vector::back, чтобы получить ссылку к данным в первой и последней позициях.

Ссылка - это ключевое слово здесь, потому что вы могли бы эффективно проверить адрес вашего итерации item и адрес соответствующих ссылок на переднюю/заднюю. В вашем примере вы берете item по значению без ссылки, чтобы этот преаксим не работал, учтите этот пример, который будет работать с этим методом:

for(auto& item : myVector) // take item by reference
{
    std::cout << item;
    if (&item == &myVector.back())
       std::cout << "(last element) " << std::endl;
    else if (&item == &myVector.front())
       std::cout << "(first element)" << std::endl;
}

Если объект перегружает адрес оператора & (хотя он считается плохой практикой), вы можете вместо этого использовать std::addressof.

Этот метод не будет работать, однако, для специализации std::vector<bool>, поскольку он оптимизирует вектор для эффективного хранения логических данных с битами, и поскольку мы не можем иметь ссылки на биты, все ссылки, извлеченные из этой структуры данных, являются прокси-объектами не точно привязаны к адресу внутренних данных.

Ответ 3

Используйте std::vector::front() для первого элемента.
Используйте std::vector::back() для последнего элемента.

Прежде чем вы вызовете эти функции, убедитесь, что vector не пуст.

    if (!orderBy.empty() && item == orderBy.back()) <--- Check if this is the last element

    else if (!orderBy.empty() && item == orderBy.front()) <-- Check if this is the first element

Ответ 4

Для сравнения на основе значения вы можете использовать myVector.front()/myVector[0] как первый и myVector.back()/myVector[myVector.size()-1] в качестве последнего элемента.

Предложение
Захватите ссылку по умолчанию, чтобы избежать нежелательных копий. например.

for(const auto& I : myVector)

Ответ 5

Вы можете искать его снова, но это было бы довольно неэффективно. Если вам нужна информация о позиции текущего элемента, вы, вероятно, захотите использовать итератор или индекс:

for (std::size_t i=0; i<myVector.size(); ++i)
{
    auto& item = myVector[i];
    std::cout << item;

    if (i == (myVector.size() - 1))
       std::cout << "(Is last element) " << std::endl;
    else if (i == 0)
       std::cout << "(Is first element)" << std::endl;
}

Ответ 6

Если у вас есть особые случаи для границ, вы должны использовать версию olтератора, но отделяя первый и последний случаи от цикла.

Если случаи передают код после этого, если вы должны инкапсулировать его в функцию.

Я не могу написать код с моего телефона: c

Ответ 7

Это работает для меня

vector<int> vi {1,2,3,4};

cout << "vi = {";
for (const auto &e : vi) {
  cout << e;

  if (&e != &vi.back())
    cout << ',';
}
cout << '}' << endl;

Ответ 8

vector<int> vi {1,2,6,4,5,6};

cout << "vi = {";

for (const auto &e : vi) 
{
  cout << e;

  if (&e != &vi.back())

    cout << ',';
}
cout << '}' << endl;

Это не сработает, поскольку третий символ совпадает с последним символом.