This question already has answers here:
Repeat contents of a std::vector
(3 answers)
Closed 9 months ago.
I have a vector
vector<int>v = {1,2,3,4,5};
I'd like to repeat the elements in the vector for, say, 3 times, such that the vector becoms
v = {1,2,3,4,5, 1,2,3,4,5, 1,2,3,4,5};
EDIT: In fact, if I need to repeat the elements for many times, say 1000, obviously I have to come with something quick and light?
How do I do it?
This can be tricky. If you want to avoid creating a temporary working object you have to be careful to avoid invalidating iterators as you go. This should do it:
std::vector<int> v = {1, 2, 3, 4, 5};
// to avoid invalidating iterators, preallocate the memory
v.reserve(v.size() * 3);
// remember the end of the range to be duplicated
// (this is the iterator we don't want to invalidate)
auto end = std::end(v);
// insert two duplicates
v.insert(std::end(v), std::begin(v), end);
v.insert(std::end(v), std::begin(v), end);
for(auto i: v)
std::cout << i << '\n';
More generally you could modify this to add multiple duplicates like this:
std::vector<int> v = {1, 2, 3, 4, 5};
std::size_t const no_of_duplicates = 1000;
// to avoid invalidating iterators, preallocate the memory
v.reserve(v.size() * no_of_duplicates);
// remember the end of the range to be duplicated
// (this is the iterator we don't want to invalidate)
auto end = std::end(v);
// insert duplicates (start from one because already have the first)
for(std::size_t i = 1; i < no_of_duplicates; ++i)
v.insert(std::end(v), std::begin(v), end);
Use the insert method of vector class
v.insert(v.end(), v.begin(), v.end());
Use std::copy
std::vector<int> v = { 1 , 2, 3, 4, 5};
std::vector<int> r;
for (auto i = 0; i < 3; ++i) {
std::copy(v.begin(), v.end(), std::back_inserter(r));
}
v.swap(r);
Related
This question already has answers here:
Appending to a vector while iterating over it?
(8 answers)
Closed 15 days ago.
I want to loop a increasing container, for example, if the container is std::vector. i need to push_back when looping the vector elements.
std::vector<int> v = {1, 3,5, 7,9};
for (auto i : v) { // v is std::vector
if (i % 2 == 1) v.push_back(i + 1); // just a demo, the push_back will happen in some condition, won't be a endless loop
printf("%d ", i);
} // the expected result is : 1, 3, 5, 7, 9, 2, 4, 6, 8, 10
I know vector is not the correct container, is there any good tools can handle this?
The problem is, as 463035818_is_not_a_number said in the comments, push_back() can (potentially) invalidates iterators. (for example, it can make std::vector to re-reallocate).
A much simpler solution is to use a for loop instead:
int main()
{
std::vector<int> v = {1, 3,5, 7,9};
for (int i = 0; i < v.size(); ++i)
{
if (v[i] % 2 == 1)
{
v.push_back(v[i] + 1);
}
std::cout << v[i] << ' ';
}
}
Link.
You can't use iterators or a range based for loop because of reallocation. But there's nothing wrong with the old-school approach of using an index. That's immune to reallocation
std::vector<int> v = {1, 3, 5, 7, 9};
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] % 2 == 1)
v.push_back(v[i] + 1);
printf("%d ", v[i]);
}
push_back invalidates iterators when the vector has to reallocate. You can resevere enough space and use an iterator based loop:
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 3,5, 7,9};
v.reserve(v.size()*2);
auto begin = v.begin();
auto end = v.end();
for (; begin != end; ++begin) {
if (*begin % 2 ==1) v.push_back(*begin + 1);
}
for (const auto& e : v) std::cout << e << " ";
}
This assumes that you only need to iterate the elements that were already in the vector before the loop. (Your code assumes that the loop iterates also the newly added ones, but the condition is such that this is not necessary. You need a second loop for printing then.)
Alternatively you could use an index based loop:
auto s = v.size();
for (size_t i=0; i < s; ++i) {
// ....
I have a std::vector<int> with duplicate values. I can find the unique values using std::unique() and std::vector::erase(), but how can I efficiently find the vector of indices and construct the original vector given the vector of unique values, through an inverse mapping vector. Allow me to illustrate this using an example:
std::vector<int> vec = {3, 2, 3, 3, 6, 5, 5, 6, 2, 6};
std::vector<int> uvec = {3, 2, 6, 5}; // vector of unique values
std::vector<int> idx_vec = {0, 1, 4, 5}; // vector of indices
std::vector<int> inv_vec = {0, 1, 0, 0, 2, 3, 3, 2, 1, 2}; // inverse mapping
The inverse mapping vector is such that with its indices one can construct the original vector using the unique vector i.e.
std::vector<int> orig_vec(ivec.size()); // construct the original vector
std::for_each(ivec.begin(), ivec.end(),
[&uvec,&inv_vec,&orig_vec](int idx) {orig_vec[idx] = uvec[inv_vec[idx]];});
And the indices vector is simply a vector indices of first occurrence of unique values in the original vector.
My rudimentary solution is far from efficient. It does not use STL algorithms and is O(n^2) at worst.
template <typename T>
inline std::tuple<std::vector<T>,std::vector<int>,vector<int>>
unique_idx_inv(const std::vector<T> &a) {
auto size_a = size(a);
std::vector<T> uniques;
std::vector<int> idx; // vector of indices
vector<int> inv(size_a); // vector of inverse mapping
for (auto i=0; i<size_a; ++i) {
auto counter = 0;
for (auto j=0; j<uniques.size(); ++j) {
if (uniques[j]==a[i]) {
counter +=1;
break;
}
}
if (counter==0) {
uniques.push_back(a[i]);
idx.push_back(i);
}
}
for (auto i=0; i<size_a; ++i) {
for (auto j=0; j<uniques.size(); ++j) {
if (uniques[j]==a[i]) {
inv[i] = j;
break;
}
}
}
return std::make_tuple(uniques,idx,inv);
}
Comparing this with the typical std::sort+std::erase+std::unique approach (which by the way only computes unique values and not indices or inverse), I get the following timing on my laptop with g++ -O3 [for a vector of size=10000 with only one duplicate value]
Find uniques+indices+inverse: 145ms
Find only uniques using STL's sort+erase+unique 0.48ms
Of course the two approaches are not exactly identical, as the latter one sorts the indices, but still I believe the solution I have posted above can be optimised considerably. Any thoughts how on I can achieve this?
If I'm not wrong, the following solution should be O(n log(n))
(I've changed the indexes in std::size_t values)
template <typename T>
inline std::tuple<std::vector<T>,
std::vector<std::size_t>,
std::vector<std::size_t>>
unique_idx_inv(const std::vector<T> &a)
{
std::size_t ind;
std::map<T, std::size_t> m;
std::vector<T> uniques;
std::vector<std::size_t> idx;
std::vector<std::size_t> inv;
inv.reserve(a.size());
ind = 0U;
for ( std::size_t i = 0U ; i < a.size() ; ++i )
{
auto e = m.insert(std::make_pair(a[i], ind));
if ( e.second )
{
uniques.push_back(a[i]);
idx.push_back(i);
++ind;
}
inv.push_back(e.first->second);
}
return std::make_tuple(uniques,idx,inv);
}
The O(n^2) arises from your approach to identify duplicates with nested loops over vectors. However, to find out if an element has already been read, a sorted vector or - imho better - an unordered map is more appropriate.
So, without writing the code here, I'd suggest to use an unordered map of the form
unordered_map<int,int>, which can hold both the unique values and the indices. I'm not sure if you still need the vectors for this information, but you can easily derive these vectors from the map.
The complexity should reduce to O(n log(n)).
This question already has an answer here:
Erasing from a std::vector while doing a for each?
(1 answer)
Closed 8 years ago.
Hello suppose that there is vector with 5 elements
vector<int> V;
for (int i=0;i<5;i++){
v.push_back(i);
}
Now how can I use find if and erase to erase values bigger than 2 from the vector ?
Would you please suggest a sample code I prepared sth but I am not sure about that.
THANKS
You can use the erase-remove idiom using std::remove_if and a suitable functor. For example
V.erase(std::remove_if(std::begin(V), std::end(V),
[](int i){ return i > 2; } ),
std::end(V) );
If you're stuck with a pre-C++11 compiler, then
bool func(int i) { return i > 2; }
V.erase(std::remove_if(V.begin(), V.end(), func), V.end());
You can remove from vector based on predicate (condition):
std::vector<int>::iterator it = std::remove_if( // it shifts, doesn't
v.begin(), v.end(), // reduces the physical size
[](int i){ return i > 2; } ));
and erase unneeded values:
v.erase( it, v.end()); // this is needed as remove_if doesn't erase
// elements that don't meet condition (are not to be
// removed), it simply moves those that don't meet
// condition to the begin.
// now we reduce the physical size
Why remove_if is followed by erase
Removing is done by shifting (by means of move assignment) the
elements in the range in such a way that the elements that are not to
be removed appear in the beginning of the range. Relative order of the
elements that remain is preserved and the physical size of the
container is unchanged. Iterators pointing to an element between the
new logical end and the physical end of the range are still
dereferenceable, but the elements themselves have unspecified values
(as per MoveAssignable post-condition). A call to remove is typically
followed by a call to a container's erase method, which erases the
unspecified values and reduces the physical size of the container to
match its new logical size.
http://en.cppreference.com/w/cpp/algorithm/remove
Example
// Let's imagine your vector is
v = { 1, 2, 3, 4, 5};
^ ^
begin end
// copy( v.begin(), v.end(), ostream_iterator<int>(cout));
will print: 12345
after remove_if vector becomes:
v = { 1, 2, 3, 4, 5};
^ ^ ^
begin it end
// copy( v.begin(), v.end(), ostream_iterator<int>(cout));
// will still print a vector of size 5: 12345
// but
// copy( v.begin(), it, ostream_iterator<int>(cout));
will print: 12
after v.erase( it, v.end()); vector becomes:
v = { 1, 2};
^ ^
begin end
// copy( v.begin(), v.end(), ostream_iterator<int>(cout));
will print: 12
compiled example
C++03:
bool f(int i) { return i > 2; }
std::vector<int>::iterator it = std::remove_if( v.begin(), v.end(), f); // shifts
v.erase( it, v.end()); // reduces the physical size
This is an alternate solution without using std::remove_if just using the erase method and iterators.
typedef std::vector<int> IntVector;
IntVector v;
// fill
for (IntVector::iterator it = v.begin(); it != v.end();) {
if (*it > 2) {
it = v.erase(it);
} else {
++it;
}
}
Is it possible to change the size of a vector in C++11 while iterating over it? Clearly the iterator will be invalidated, but can the following clean syntax still be used?
std::vector<some_type> vec;
for(auto elem : vec) {
if(condition(elem)) {
new_elem = function(elem);
vec.insert(iterator_associated_with_elem+1, new_elem);
}
//Don't insert on condition(new_elem)
}
If not, what is the cleanest code to accomplish this task?
No, you can't. The standard mandates that the raged-based for behaves like a given algorithm. This algorithm uses iterators, which get invalidated when you modify the vector.
The simplest way for me is to to use iterators. Note that when we insert, we also reassign the iterator so that we always have a valid iterator:
auto it = vec.begin();
while(it < vec.end()) {
if (condition(*it)) {
new_elem = function(*it);
it = vec.insert(it + 1, new_elem);
}
++it;
}
No, you cannot use this trick, because there is an iterator behind your range loop. Once that iterator is invalidated, you cannot reference it again.
You can use this construct if you exit the loop immediately after the insertion. Otherwise, you need to use an index-based loop that starts at the back, and goes down to zero to avoid "seeing" elements that have been inserted during the execution of the loop.
std::vector<some_type> vec;
for(int i = vec.size()-1 ; i >= 0 ; i--) {
const some_type& elem(vec[i]);
if(condition(elem)) {
vec.insert(vec.begin()+i+1, function(elem));
}
//Don't insert on condition(new_elem)
}
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto &val : vec)
{
static int i = 0;
if (val == 5)
{
vec.insert(vec.begin() + i + 1, 6);
}
++i;
}
Values of vec will then be: 1 2 3 4 5 6
My question is very similar to How to find an item in a std::vector? However, I want to go further, suppose the item I am searching for appears several times in the vector, and I want to obtain its positions in the vector as well. For example, the vector I have is [ 1 3 4 3 7], and the item I want to search is 3. Then the positions of the item is 1 and 3. Using the std::find function, I can only obtain its first position in the vector. Any ideas?
Just stick it in a while loop,
auto i = std::find(v.begin(), v.end(), n);
std::vector<std::size_t> result;
while(i != v.end())
{
result.push_back(std::distance(v.begin(), i));
i = std::find(i + 1, v.end(), n);
}
Use std::find successive times, and then put all the results together. Use as first of the range in which you find, the position that the previous std::find returned to you plus one.
You can use std::find multiple times:
std::vector<int> vec;
// fill the vector with numbers
std::vector<int>::iterator it = vec.begin();
while (it != vec.end())
{
it = std::find(it, vec.end(), 3);
// do something with *it
if (it != vec.end())
it++;
}
Or you can simply use std::for_each:
std::vector<int> vec;
// fill the vector with numbers
std::for_each(vec.begin(), vec.end(), [&](int i)
{
if (i == 3)
{
// do something
}
});
If you are looking for the indexes/iterators for the items, you can simply use a custom loop:
std::vector<int> vec;
// fill the vector with numbers
std::vector<int> results;
for (std::size_t i = 0; i < vec.size(); ++i)
{
if (vec[i] == 3)
{
results.push_back(i);
}
}
results will then hold all of the indexes for elements matching your criteria (in this case, ==3).