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) {
// ....
Related
I have a below program. I need to understand why do we need to decrement pointer when we use erase method?
Also is there any better way which does not create a such confusion ?
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> myvector{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto i = myvector.begin(); i != myvector.end(); ++i) {
if (*i % 2 == 0) {
myvector.erase(i);
i--;// why do we need to decrement ?
}
}
// Printing the vector
for (auto it = myvector.begin(); it != myvector.end(); ++it)
cout << ' ' << *it;
return 0;
}
I need to understand why do we need to decrement pointer when we use erase method?
You don't, and shouldn't. The correct thing to do is use the return value of erase. At the moment your program has undefined behaviour because you are modifying an invalid iterator.
for (auto i = myvector.begin(); i != myvector.end();) {
if (*i % 2 == 0) {
i = myvector.erase(i);
} else {
++i;
}
}
Also is there any better way which does not create a such confusion ?
Yes, std::remove_if
auto is_even = [](int i){ return (i % 2) == 0; };
auto last = std::remove_if(myvector.begin(), myvector.end(), is_even);
myvector.erase(last, myvector.end());
You have a good answer from Caleth, but I'm going to add some information:
for (auto i = myvector.begin(); i != myvector.end(); ++i) {
if (*i % 2 == 0) {
myvector.erase(i);
i--;// why do we need to decrement ?
}
}
That's your code. For my explanation, let's believe that the iterator is just an index (an int). It's not, but it works for understanding.
Let's say myvector contains the integers 0..10 and you delete 4. Once you do:
0 1 2 3 5 6 7 8 9 10
Now, imagine your loop. You get to the bottom of the for-loop and increment i -- it now has 5, but you skip over checking if the old myvector[5] -- which is now stored in myvector[4] -- fits your if-statement.
The other way to write this:
for (auto i = myvector.begin(); i != myvector.end(); ) {
if (...) ...
else {
++i;
}
}
That is, you only increment the iterator if you do NOT delete. This avoids skipping over the item after the one you deleted (because it moved into the deleted guy's spot).
However, this is the wrong way to do it, and Caleth has better answers for how to do it properly.
I have been trying to solve this problem:
Given an array of integers, return indices of the two numbers such
that they add up to a specific target.
You may assume that each input would have exactly one solution,
and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
I have been trying to solve this using map and my attempted solution is below:
#include <iostream>
#include <map>
#include <vector>
using namespace std;
vector<int> twoSum(vector<int>& nums, int target) {
std::map<int, int> indices;
for (int i = 0; i < nums.size(); ++i) {
auto it = indices.find(target - nums[i]);
if (it != indices.end())
return {it->first, i};
indices[i] = nums[i];
}
return {};
}
int main() {
std::vector<int> nums = {2, 7, 11, 15};
int target = 9;
std::vector<int> ans = twoSum(nums, target);
for(const auto &elem : ans) {
std::cout << elem << " ";
}
std::cout << "\n";
return 0;
}
To avoid two for loops, I'm trying to find target - num2 because num1 + num2 = target.
So, the logic is to
create a map from the input vector nums
use map.find(target - num[i])
return the first value of iterator pointing to target-nums[i], i.e., the key for the value = target-nums[i], in the map and i.
Therefore, for the above code, the function should return {0, 1}
However, every time, I get an empty vector. Could anyone please tell me whether my logic is wrong or I'm manipulating the map or vector wrongly?
You are very close to solving the problem but your code has a small yet critical issue.
You add elements to your map as (key=index, value=number)
indices[i] = nums[i];
... Essentially, you just recreated the array in a different format, so if you think about it, for every i, nums[i] == indices[i]. This approach really doesn't get you any further in solving your problem.
Instead, you should try mapping (key=number, value=index)
indices[nums[i]] = i;
This way, when you search the map for a previously-encountered number as you already are
auto it = indices.find(target - nums[i]);
... You end up searching for the number itself instead of an index!
Note that you will also need to change the return to use the index instead of the value, as the format of your map is now different
auto it = indices.find(target - nums[i]);
if (it != indices.end())
return {it->second, i};
try doing: indices[num[i]] = 1.
You are using the index as the key of the map, but you should really be using the values.
Don't use a map at all.
std::vector<int> twoSum(const std::vector<int> & nums, int target) {
for (int it1 = nums.begin(); it1 != nums.end(); ++it1) {
auto it2 = std::find(std::next(it1), nums.end(), target - *it1);
if (it2 != nums.end())
return {std::distance(nums.begin(), it1), std::distance(nums.begin(), it2)};
}
// You can assume this is never reached, throwing is noisier than returning empty
throw std::runtime_error("invalid arguments to twoSum");
}
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);
I am working on a problem where I have to create subvectors from a bigger vector. If the elements in the vector are consecutive I have to create a vector of those elements. If there are elements which are not consecutive then a vector of that single elements is created. My logic is as below
vector<int> vect;
for (int nCount=0; nCount < 3; nCount++)
vect.push_back(nCount);
vect.push_back(5);
vect.push_back(8);
vector<int>::iterator itEnd;
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
The functor NotConsecutiveis as below
return (int first != int second-1);
So I am expecting the std::adjacent_find will give me back the iterators such that I can create vector one{0,1,2,3}, vector two{5} and vector{8}. But I am not sure if there is any simpler way?
Edit:I forgot to mention that I have std::adjacent_find in a loop as
while(itBegin != vect.end())
{
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
vector<int> groupe;
if( std::distance(itBegin, itEnd) < 1)
{
groupe.assign(itBegin, itBegin+1);
}
else
{
groupe.assign(itBegin, itEnd);
}
if(boost::next(itEnd) != vect.end())
{
itBegin = ++itEnd;
}
else
{
vector<int> last_element.push_back(itEnd);
}
}
Does it make any sense?
I think this is what is being requested. It does not use adjacent_find() but manually iterates through the vector populating a vector<vector<int>> containing the extracted sub-vectors. It is pretty simple, IMO.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vect { 0, 1, 2, 3, 5, 8 };
// List of subvectors extracted from 'vect'.
// Initially populated with a single vector containing
// the first element from 'vect'.
//
std::vector<std::vector<int>> sub_vectors(1, std::vector<int>(1, vect[0]));
// Iterate over the elements of 'vect',
// skipping the first as it has already been processed.
//
std::for_each(vect.begin() + 1,
vect.end(),
[&](int i)
{
// It the current int is one more than previous
// append to current sub vector.
if (sub_vectors.back().back() == i - 1)
{
sub_vectors.back().push_back(i);
}
// Otherwise, create a new subvector contain
// a single element.
else
{
sub_vectors.push_back(std::vector<int>(1, i));
}
});
for (auto const& v: sub_vectors)
{
for (auto i: v) std::cout << i << ", ";
std::cout << std::endl;
}
}
Output:
0, 1, 2, 3,
5,
8,
See demo at http://ideone.com/ZM9ssk.
Due to the limitations of std::adjacent_find you can't use it quite the way you want to. However it can still be useful.
What you can do is to iterate over the collection, and use std::adjacent_find in a loop, with the last returned iterator (or your outer loop iterator for the first call) until it returns end. Then you will have a complete set of consecutive elements. Then continue the outer loop from where the last call to std::adjacent_find returned a non-end iterator.
Honestly, I don't find any clear disadvantage of using a simple hand-crafted loop instead of standard functions:
void split(const std::vector<int> &origin, vector<vector<int> > &result)
{
result.clear();
if(origin.empty()) return;
result.resize(1);
result[0].push_back(origin[0]);
for(size_t i = 1; i < origin.size(); ++i)
{
if(origin[i] != origin[i-1] + 1) result.push_back(vector<int>());
result.back().push_back(origin[i]);
}
}
I've std::vector<type> myVector
lets say content is:
el1, el2, el3, splitElement, el4,el5
I'm splitting splitElement into split1 and split2
I want to have vector:
split2, el4, el5, el1, el2, el3, split1
Split2 should be begining, split1 end. Other elements order should be like in example. Let's treat vector as chain. I want to insert two elements and shift chain to make split2 first element.
What is the elegant and effective way doing it using stl.
My fast code for now (it's very ugly solution):
std::vector<type> before;
std::vector<type> after;
bool afterBool = false;
for(std::vector<type>::iterator it = myVector.begin(); it != myVector.end(); it++)
{
if(*it == splitElement)
{
afterBool = true;
before.push_back(split1);
after.push_back(split2);
}
else if(afterBool)
after.push_back(*it);
else
before.push_back(*it);
}
myVector.clear();
for(std::vector<type>::iterator it = after.begin(); it != after.end(); it++)
myVector.push_back(*it);
for(std::vector<type>::iterator it = before.begin(); it != before.end(); it++)
myVector.push_back(*it);
I've added it only cause I don't wanted to leave topic without any code.
How to do it in nice way?
Example:
std::vector<int> myvector = {1, 2, 3, 0, 4, 5};
int splitElement = 0;
int split1 = -1;
int split2 = -2;
First you find your splitElement:
auto it = std::find(myvector.begin(), myvector.end(), splitElement);
Then you rotate the vector at the point you found splitElement, using std::rotate algorithm:
std::rotate(myvector.begin(), it, myvector.end());
// this yields { 0, 4, 5, 1, 2, 3 }
And finally just assign split2 to the beggining and push split1 to the back:
myvector[0] = split2;
myvector.push_back(split1);
The vector now looks like this: {-2, 4, 5, 1, 2, 3, -1}.
It sounds like you want to partition your vector. So you can use std::partition
To take your example with integers and -1 as the split element.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Splitter
{
int split;
Splitter(int sp):split(sp){}
bool operator()(int i)
{
return split < i;
}
};
int main () {
vector<int> myvector;
vector<int>::iterator it, bound;
// set some values:
for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
bound = partition (myvector.begin(), myvector.end(), Splitter(5));
myvector.insert(bound, -1);
cout << "odd members:";
for (it=myvector.begin(); it!=myvector.end(); ++it)
cout << " " << *it;
cout << endl;
return 0;
}
Since you havent mentioned about the sorting requirement and < operation on the type.
i guess you just want to split the element and make the first split as the last element in a vector and second split as the first element of the vector
I guess the better way to do this is to use a Data structure (Linked list)
store the elements of the vector in LL
traverse the list till the split element
make the second element as head and first element as the tail of LL
the original tail should be pointing its next to original tal.
aftere these above operation are done.just traverse the ll and store back in a vector.