Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get adjacent pairs of elements from vector via iterator in c++

Tags:

c++

I want to iterate over all adjacent pairs elements in a vector. For example, if I have a vector {1, 2, 3, 4}, I want my iterator to return the following:

(1, 2)
(2, 3)
(3, 4)

I know how to iterate over one element at a time using the following:

vector<int> numbers == {1, 2, 3, 4};
for (vector<int>::const_iterator it = numbers.cbegin(); 
     words != numbers.cend(); 
     ++it) 
{
    cout << *it << endl;
}

But I don't know how to get the next element as well.

like image 692
Vivek Avatar asked Apr 04 '19 05:04

Vivek


4 Answers

Vector's iterator is random access iterator. You can use operator[] on the iterator to get next element like this: it[1]

like image 186
wilx Avatar answered Nov 15 '22 20:11

wilx


std::vector::iterator can be used almost like a pointer.

Make sure the conditional of the loop is altered and use *(it+1) in the loop.

vector<int> numbers = {1, 2, 3, 4}; // One =, not two.

// If the vector is empty, skip the block.
if ( !numbers.empty() )
{
   vector<int>::const_iterator end = numbers.cend() - 1;

   for (vector<int>::const_iterator it = numbers.cbegin(); it != end; ++it) {
      cout << '(' << *it << ',' << *(it+1) << ')' << endl;
   }
}

Working demo.

like image 37
R Sahu Avatar answered Nov 15 '22 18:11

R Sahu


for (auto it = numbers.cbegin(); it != numbers.end() && std::next(it) != numbers.end(); ++it)
{
    cout << *it << " " << *std::next(it) << endl;

    // or, abusing C++17
    auto&& [first, second] = std::tie(*it, *std::next(it));
    cout << first << " " << second << endl;
}

If you really want an iterator that will yield the pair, I've hastily put together one for a proof of concept. Beware it's not extensively tested.

Usage:

for (auto&& [first, second] : AdjacentRange{numbers})
{
    cout << first << " " << second << endl;
}

// or

for (auto&& pair : AdjacentRange{numbers})
{
    cout << pair.first << " " << pair.second << endl;
}

Implementation:

template <class It>
struct AdjancetRangeIt
{
    It it_;

    auto operator*() const
    {
        return std::tie(*it_, *std::next(it_));
    }

    auto operator++() -> auto& { ++it_; return *this; }
    auto operator!=(AdjancetRangeIt other) const { return it_ != other.it_; }
};

template <class It>
AdjancetRangeIt(It) -> AdjancetRangeIt<It>;

template <class It>
struct AdjacentRange
{
    It begin_, end_;

    template <class C>
    AdjacentRange(C& container)
        : begin_{std::begin(container)}, end_{std::end(container)}
    {}

    auto begin() const
    {
        return AdjancetRangeIt{begin_};
    }
    auto end() const
    {
        if (begin_ == end_)
            return AdjancetRangeIt{end_};
        else
            return AdjancetRangeIt{std::prev(end_)};
    }
};

template <class C>
AdjacentRange(C) -> AdjacentRange<typename C::iterator>;
like image 2
bolov Avatar answered Nov 15 '22 19:11

bolov


You can iterate over two elements at the same time:

std::vector<int> v{1,2,3,4};

for (auto l = v.begin(), r = l + 1, e = v.end(); r != e; ++l, ++r)
    std::cout << '(' << *l << ", " << *r << ")\n";

Outputs:

(1, 2)
(2, 3)
(3, 4)

Check it out in Wandbox.

like image 1
PaperBirdMaster Avatar answered Nov 15 '22 19:11

PaperBirdMaster