Best way to extract a subvector from a vector?
Suppose I have a std::vector
(let's call it myVec
) of size N
. What's the simplest way to construct a new vector consisting of a copy of elements X through Y, where 0 <= X <= Y <= N-1? For example, myVec [100000]
through myVec [100999]
in a vector of size 150000
.
If this cannot be done efficiently with a vector, is there another STL datatype that I should use instead?
vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
vector<T> newVec(first, last);
It's an O(N) operation to construct the new vector, but there isn't really a better way.
Just use the vector constructor.
std::vector<int> data();
// Load Z elements into data so that Z > Y > X
std::vector<int> sub(&data[100000],&data[101000]);
This discussion is pretty old, but the simplest one isn't mentioned yet, with list-initialization:
vector<int> subvector = {big_vector.begin() + 3, big_vector.end() - 2};
It requires c++11 or above.
Example usage:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
vector<int> big_vector = {5,12,4,6,7,8,9,9,31,1,1,5,76,78,8};
vector<int> subvector = {big_vector.begin() + 3, big_vector.end() - 2};
cout << "Big vector: ";
for_each(big_vector.begin(), big_vector.end(),[](int number){cout << number << ";";});
cout << endl << "Subvector: ";
for_each(subvector.begin(), subvector.end(),[](int number){cout << number << ";";});
cout << endl;
}
Result:
Big vector: 5;12;4;6;7;8;9;9;31;1;1;5;76;78;8;
Subvector: 6;7;8;9;9;31;1;1;5;76;
std::vector<T>(input_iterator, input_iterator)
, in your case foo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);
, see for example here
These days, we use span
s! So you would write:
#include <gsl/span>
...
auto start_pos = 100000;
auto length = 1000;
auto span_of_myvec = gsl::make_span(myvec);
auto my_subspan = span_of_myvec.subspan(start_pos, length);
to get a span of 1000 elements of the same type as myvec
's. Or a more terse form:
auto my_subspan = gsl::make_span(myvec).subspan(1000000, 1000);
(but I don't like this as much, since the meaning of each numeric argument is not entirely clear; and it gets worse if the length and start_pos are of the same order of magnitude.)
Anyway, remember that this is not a copy, it's just a view of the data in the vector, so be careful. If you want an actual copy, you could do:
std::vector<T> new_vec(my_subspan.cbegin(), my_subspan.cend());
Notes:
-
gsl
stands for Guidelines Support Library. For more information aboutgsl
, see: http://www.modernescpp.com/index.php/c-core-guideline-the-guidelines-support-library. - There are several
gsl
implementations . For example: https://github.com/martinmoene/gsl-lite - C++20 provides an implementation of
span
. You would usestd::span
and#include <span>
rather than#include <gsl/span>
. - For more information about spans, see: What is a "span" and when should I use one?
-
std::vector
has a gazillion constructors, it's super-easy to fall into one you didn't intend to use, so be careful.