Easy way to copy the first nth values of a set into a vector in C++

Viewed 577

Simple question, let's say I save a set with 5 values and I want to copy the first 3 values into a vector, is there a fast easy way to do that? I know that if I want to copy an entire set into a vector I can just use something like this:

set <int> test = {0,1,2,3,4,5};
vector<int> vect(test.begin(),test.end());

Can I do something similar to only copy the first n values? I've been using a for loop to do this but I was just curious to check if there was a faster way to code it.

3 Answers

To get an iterator n steps from the begin of a std::set, std::next yields the abstraction you need.

std::vector<int> vec(test.cbegin(), std::next(test.cbegin(), 5));

This is due to std::set providing bidirectional iterators, so you can't use arithmetics like test.cbegin() + 5. std::next solves this for you.

std::set::iterator is a bidirectional iterator not a random access one, hence use std::next`, as follows

#include <algorithm>
#include <set>
#include <vector>
#include <iostream>

int main() {
    std::set <int> test = {0,1,2,3,4,5};
    size_t n=3;
    std::vector<int> vect;
    if(test.size() >= n) vect = std::vector<int>{test.begin(),std::next(test.begin(),n)};

    std::for_each(vect.begin(), vect.end(), [](auto el){std::cout << el <<" ";});
}

Demo

The problem with the std::next() answers is that std::next() is inherently unsafe. If there weren't actually 5 elements in the set you'd keep iterating past the end iterator - and that's undefined behavior.

If you use range-v3 instead, this is a solution which is both safe and, in my opinion, more expressive:

auto vect = test
          | views::take(5)
          | ranges::to<std::vector>();

This will take up to the first 5 elements of the set and construct a vector out of the resulting range. views::take is in C++20, although ranges::to is unfortunately not.

Demo.

Related