Check if the element is the first or the last one in an std::vector

31,156

Solution 1

You shouldn't use the range-based for in this case, as this kind of for "hides" the iterator, and you'd need an additional counter to keep track of the position in vector. You can simply do

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

Note that simply comparing my.Vector.back() with your element from a range-based for is OK only if you're sure that you don't have duplicates in the vector. But if e.g. the value of the last element appears multiple times in the vector, you're going to find only its first position. So that's why there's really no good way of using a range-based for without an additional index that keeps track of where exactly in the vector you are.

EDIT See also @thelink2012's answer for how to "trick" your range-based for so you can get the position of the element implicitly.

Solution 2

Use the std::vector::front and std::vector::back to get a reference to the data in the first and last positions.

Reference is a keyword here because you could efficiently check the address of your iterating item and the address of the respective front/back references. In your example you take the item by value not reference so this prehaps wouldn't work, take in consideration this example that'd work with this method:

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

If the object overloads the address of operator & (though it's considered a bad practice) you might want to use std::addressof instead.

This method won't work however for the std::vector<bool> specialization since it optimizes the vector to store booleans efficiently with bits, and since we cannot have references to bits, all references taken out this data structure is a proxy object not exactly tied to the address of the internal data.

Solution 3

Use std::vector::front() for the first element.
Use std::vector::back() for the last element.

Before you call those functions, make sure that the vector is not empty.

    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

Solution 4

For value based comparison, you may use myVector.front()/myVector[0] as the first and myVector.back()/myVector[myVector.size()-1] as the last element.

Suggestion
Capture the reference by default to avoid unwanted copies. e.g.

for(const auto& I : myVector)

Solution 5

If you have special cases for the boundaries you should use the ol' iterator version, but separating the first and last cases away from the loop.

If the cases share the code after that if you should encapsulate it on a function.

I can't write code from my phone :c

Share:
31,156

Related videos on Youtube

Mendes
Author by

Mendes

BY DAY: Working hard to turn ideas into borderline software BY NIGHT: Family, fun, barbecue and rockn´roll - go to sleep and brand new ideas again... C++, Javascript, MEAN, ReactJs, Relay and naturally C++ (never missing it) Forerunner into future.... http://stackrating.com/badge/Mendes

Updated on July 08, 2020

Comments

  • Mendes
    Mendes almost 4 years

    I have the following for each C++ code:

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

    Of course IfLast() and IfFirst() do not exist on std::vector. Is there a native std:: way to check for first and last element ?

    • squid
      squid about 9 years
      If it is only special operations on head/tail elements, consider bring it out of loop.
    • Chen OT
      Chen OT about 9 years
      Prefer for(auto& item: myVector) or for(const auto& item: myVector) to prevent copy and mutable.
    • pattivacek
      pattivacek over 6 years
      Another pre-C++11 version: stackoverflow.com/questions/151046/…
  • T.C.
    T.C. about 9 years
    ,1 is redundant; or even it + 1 is fine.
  • Mendes
    Mendes about 9 years
    Can´t understand why I should not use it. Is this a bad practice ? Indeed I don´t need the iterator, but the item element...
  • johnsyweb
    johnsyweb about 9 years
    You may also wish to consider a vector whose first element is also its last element :-)
  • vsoftco
    vsoftco about 9 years
    @Mendez it's not a bad practice. Depends on the scenario. If you want to track the position in the vector, it's better to loop using iterators. If you just want to e.g. display the elements (and not their position), then a range-based for is OK.
  • vsoftco
    vsoftco about 9 years
    what if the vectors has the last element duplicated? It's not gonna work, you have to keep track of the index.
  • R Sahu
    R Sahu about 9 years
    @vsoftco, I don't know what the OP's intention is for those checks. Given the posted code they either (1) don't expect to see duplicates, or (2) want to see the output multiple times.
  • vsoftco
    vsoftco about 9 years
    I almost said you're wrong. But taking by reference works here, +1.
  • vsoftco
    vsoftco about 9 years
    It will break on std::vector<bool> :P (the latter return proxies in a range-based for, which are rvalues, and it's not really a container) But still, nice answer.
  • Denilson Amorim
    Denilson Amorim about 9 years
    @vsoftco Very good point that might easily get unoticed! I've updated the answer. Much thanks for the heads up :)
  • Matthieu M.
    Matthieu M. about 9 years
    @vsoftco: let's hope nobody uses this aberration.
  • vsoftco
    vsoftco about 9 years
    @MatthieuM. you mean vector<bool> or the answer? The answer is fine IMO, there's nothing wrong that can happen (unless of course your vector elements overload operator&). And even vector<bool> has its usage.
  • Matthieu M.
    Matthieu M. about 9 years
    @vsoftco: vector<bool>; there are issues with using proxies, and some expected usage can fail unexpectedly. Regarding the address, std::address_of avoids the issue, though it's more verbose.
  • vsoftco
    vsoftco about 9 years
    @MatthieuM. Yes then I agree. However Howard makes a good point about proper usage of std::vector<bool>, I read it and it changed my mind a bit.
  • Matthieu M.
    Matthieu M. about 9 years
    @vsoftco: Oh I agree, some people proposed the name dynamic_bitset for example; but not backward compatible so unlikely to come...
  • vsoftco
    vsoftco about 9 years
    @MatthieuM. Yes I agree, implementing it as a specialization of vector is a bad idea.
  • StaticBeagle
    StaticBeagle over 6 years
    Someone posted a similar answer earlier in this same question stackoverflow.com/a/30205291/6383857