What is more efficient? vector.assign vs vector.erase - c++

When a vector exists and tries to erase the back of that vector.
Is it efficient to use an 'vector.assign' in terms of time complexity? Or is it efficient to use 'vector.erase'?
Please let me know the time complexity in each case.
[For example]
vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 1. use assign
v.assign(v.begin(), v.begin() + 5);
// 2. use erase
v.erase(v.begin() + 5, v.end());

I would like to use vectors that consist only of elements from the beginning section of vectors to a certain index.
It's most efficient to use resize, because that's what that function is for.
For what its worth, self-assignment is not allowed for containers.

Related

Delete Row in 2D Vector C++

So I have the example vector initialized as so:
vector<vector<int> > v = {{1, 2, 3},{4, 5, 6},{7, 8, 9}}
I want to totally delete the row, {4, 5, 6} such that v[1][0] references 7 and the final vector is v = {{1, 2, 3},{7, 8, 9}}
v[1].clear() does not accomplish this, and v[1].erase(v[1].begin(),v[1].begin()+3) doesnt seem to either unless I am just an idiot.
Thank you in advance!
You should erase whole nested vector, not just items inside.
If you writing v[1].erase(v[1].begin(),v[1].begin()+3), you got {{1,2,3},{},{7,8,9}}.
Just write what Albin Paul said: v.erase(v.begin() + 1) and then your vector will be v = {{1,2,3},{7,8,9}}.
Adding onto Vslav, if the vector you want to delete is conveniently at the end of your 2d matrix, then just do v.popback(). It is simpler but only works on the final element. You could also do some research on remove() function.

Is there any standard variadic function for erasing multiple elements in a vector?

Take this vector:
std::vector<int> v = {1, 2, 3, 4, 5};
Let's say I want to remove some elements of a vector at some arbitrary indices: 0, 1, and 3. It's tedious to have to write something like this:
v.erase(v.begin());
v.erase(v.begin());
v.erase(v.begin() + 1);
Is there any standard function that takes in an arbitrary number of indices to erase from a vector? Something like this: v.erase(0, 1, 3);
Yes and no.
There's nothing that deals with indices. There's also nothing that deals with arbitrary elements.
But you can erase multiple items that form a contiguous range at once. So you can coalesce your first two calls to erase into one (and probably about double the speed in the process).
// erase the first two elements
v.erase(v.begin(), v.begin() + 2);
If you want to erase first three element so for this you can run.
std::vector<int> v = {1, 2, 3, 4, 5};
v.erase(v.begin(),v.begin()+3);
or,
v.erase(v.begin(),v.end()-2);

Using switch case with multidimensional array in C++

I want to start out by saying that I am really new to C++ and have not been able to find an answer to this question yet. It is for a school project and my teacher has not been very helpful.
I wanted to know how to use a switch statement with a multidimensional array. For example, say we have this array:
int arr[3][5] = {{1, 3, 1, 1, 2}, {1, 2, 4, 5, 6}, {6, 3, 4, 3, 5}};
How would I use a switch statement in order to locate the individual rows and check for certain criteria within them?
Edit: I think it is best if I clarify a bit. I want to check the conditions of the elements in each row, not just the individual elements themselves.
So I may check if there are 1's in the first subarray, check for 3's in the second subarray, and check for 4's in the last subarray.
Short answer; you wouldn't. swtich is not the right tool for the job. You are searching for some criteria right? In the absence of a specific criteria, lets say that you are interested in if the sub array contains a 1.
We can formulate this with a function:
bool contains_a_1(int arr[5]) {
return std::any_of( // This is an algorithm that will check if any of them
// match the predicate below
std::begin(arr), std::end(arr), // This is the range to check over
[](int v) { return v == 1; } // This is a simple lambda function that tells the
// algorithm what we are looking for.
);
Now we have a function that checks our condition. So now we need to check it, but how? If we want to check if any of the arrays in our array meet this condition, we have already seen a thing that can help us with this, std::any_of:
int arr[3][5] = {{1, 3, 1, 1, 2}, {1, 2, 4, 5, 6}, {6, 3, 4, 3, 5}};
bool there_is_a_one_somewhere = std::any_of(std::begin(arr), std::end(arr), contains_a_1);
Or maybe you want this bool for each value in the array:
std::array<bool, 3> contains_1;
std::transform(std::begin(arr), std::end(arr), std::begin(contains_1), contains_a_1);
Or maybe you want to do something else? Well, there is probably an algorithm for that! You just need to find the right one here in <algorithm>.
So I may check if there are 1's in the first subarray, check for 3's in the second subarray, and check for 4's in the last subarray.
You can use for loops to iterate over the rows and std::find to check whether the subarray contains a particular element or not as shown below:
#include <iostream>
#include <algorithm>
int main()
{
int arr[3][5] = {{1, 3, 1, 1, 2}, {1, 2, 4, 5, 6}, {6, 3, 4, 3, 5}};
//iterate over rows
for(auto &row: arr)
{
bool exists = std::find(std::begin(row), std::end(row), 1) != std::end(row); //check if 1 is present in the current row
std::cout<<"element "<<(exists?"is present":"not present")<<std::endl;
}
}
In the above code, we have checked whether 1 is present in the subarray or not. Similarly you can check for other values like 3 or 4.

vector erase multiple regions, 2 x erase vs single assign?

I need to erase 2 ranges of elements from vector, the vector looks like this:
std::vector<int> vec {0, 1, 2, 3, 4, 5, 6, 7};
for example I need to keep only numbers 3 and 4. (in reality this could be big objects)
There are 2 options:
1) take target elements and drop the rest:
vec.assign(vec.begin() + 3, vec.begin() + 5);
2) explicitly remove ranges:
vec.erase(vec.begin() + 6, vec.end()); // first end (it's cheap)
vec.erase(vec.begin(), vec.begin() + 3); // then beginning (reallocates elements)
Which one of these 2 options will perform faster?
Or is there even better way?
You can use a single std::copy followed by std::vector::erase. It's correct and likely uses memcpy or memmove for POD types so it should be fast. Something like:
auto itr = std::copy(vec.begin() + 3, vec.begin() + 5, vec.begin());
vec.erase(itr, vec.end());
If the vector elements are movable you could use the std::move algorithm instead of std::copy.

Iterator out of range run time exception with an iteration by 2 in a for loop

Here is a piece of my code:
vector<int> v {1, 2, 10, 4, 5, 6, 7, 8, 9 };
for (auto i = v.begin(); i != v.end(); i = i + 2) {
cout << (*i) << " ";
}
What I want to do is to advance the iterator by 2 elements after each iteration. However, there is a runtime exception: offset out of range. So my question is:
Is there a way to iterate by 2 elements each time with a for loop and if possible, can the condition to prevent this exception be defined in the for() statement?
Is there a way to iterate by 2 elements each time with a for loop and
if possible, can the condition to prevent this exception be defined in
the for() statement?
Sure there is a way. The most natural would be this
vector<int> v {1, 2, 10, 4, 5, 6, 7, 8, 9 };
for (size_t i=0; i < v.size(); i = i + 2) {
cout << v[i] << " ";
}
Iterators (just like anything else) arent the best tool for every situation. Iterators are meant to be an abstraction that does not care about an index. Thus when you actually do care about the index, I would not use iterators, but a plain index based loop. Of course its a matter of taste, but being so much used to loops that go from begin to end incremented via ++it, it can help a lot to distinguish a loop that deviates from this usual pattern.
As #tobi303 said, the most suitable way for you is to use indexes and not iterators. Anyway, there's a reason for the Out of Range Exception. If you try with this vector (or in general if you add another element to it):
{1, 2, 10, 4, 5, 6, 7, 8, 9, 1 }
You won't obtain that exception. This is what the doc says about the end method:
Returns an iterator referring to the past-the-end element in the vector container.
The past-the-end element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced.
So, when *i is equal to 9, and the for loop checks for the end of the vector, it will go on. But if you add 2 to i, the end method will never match the actual end.