I face a common problem in my code where I would like to remove only a single element from a reversed std::vector after it satisfies a predicate. I understand there's a number of ways to do this with ranges-v3, but each way I come up with seems a bit convoluted.
Here's an example of the target vector v:
std::vector v = { 1, 2, 3, 2, 4 };
The result needs to be vector r:
std::vector r = { 1, 2, 3, 4 };
Which will be done by removing the first 2 (via a lambda predicate "is_two") that is found when reverse traversing the vector v.
Here's one what it could look like in a vanilla C++ raw loop:
auto is_two = [](int a) { return a == 2; };
for (int i = v.size(); --i >= 0;) {
if (is_two(v[i])) {
v.erase(v.begin() + i);
break;
}
}
Here's my bad ranges-v3 version:
namespace rs = ranges;
namespace rv = ranges::view;
namespace ra = ranges::action;
rs::for_each(v | rv::enumerate
| rv::reverse
| rv::filter([](auto i_e) { return i_e.second == 2; })
| rv::take(1),
[&](auto& i_e) { v.erase(v.begin() + i_e.first); });
Ideally I'm wondering if there's some solution that could look something like this:
ra::remove_if(v | rv::reverse, is_two);
To generalize, I'd like to know how one can take a container, pipe it through some ranges::view operations, then remove the elements in the resulting range from the original container.
Since no one seems to have come up with a better approach,
I would like to mention for your benefit the possibility of resorting to good old reverse_iterators.
vec.erase(std::prev(ranges::find_if(vec.rbegin(), vec.rend(), is_two).base()));
Admittedly, this is not very ranges-ish,
but least it works.
The main purpose of range-based for loops is consistency. Having the same operation executed for each element.
Deleting an element breaks this consistency. So the best solution is a normal for loop where you can use iterators and breaks.
When you have a hammer everything looks like a nail. Don't hammer the ranged loop into a normal one.
Related
Python's itertools has the islice(seq, start, stop, step) procedure that takes a sequence and returns an iterator of every stepth value of the sequence values between start and stop.
Does the Ranges library of C++20 provide a similar functionality, e.g. a function like slice that takes a random access iterator start, a sentinel stop, and a step value step, and that returns a random access iterator that iterates over every stepth value between start and stop?
In case it does not, can such an iterator adapter be implemented using the primitives provided by the Ranges library?
(I know how I can implement such an adapter by hand, so this is not the question.)
Not quite.
C++20 will have view::iota which gives you a sequence from a starting value to a sentinel. However, it does not have the stride functionality. It only increments (via ++).
However, you can combine it with range-v3's view::stride to add in the steps. That is:
auto evens = view::iota(0, 100) | view::stride(2); // [0, 2, 4, 6, ... ]
For existing ranges, there's view::slice, which also doesn't take a stride. But these are orthogonal and layer nicely:
auto even_teens = view::iota(0, 100)
| view::slice(10, 20)
| view::stride(2); // [10, 12, 14, 16, 18]
Unfortunaltely, slice and stride of Range-v3, as presented in Barry'sanswer, are not (yet) available in the Ranges library of C++20.
However, you can replace slice by combining std::views::drop_while and std::views::take_while. To replace stride, you can use the range adaptor std::views::filter and pass a specific lambda expression to it. To filter for every other element as in Barry's example, I would use a stateful lambda expression with an init capture. You can put everything together to represent the range [10, 12, 14, 16, 18] as follows:
auto even_teens = std::views::iota(0, 100)
| std::views::drop_while([](int i) { return i < 10; })
| std::views::take_while([](int i) { return i < 20; })
| std::views::filter([s = false](auto const&) mutable { return s = !s; });
For a more universal stride solution, you can use a counter along with the modulo operator in the lambda expression. To be able to specify the stride size n in a readable way, I would use the following lambda expression, which provides another lambda expression that keeps track of the stride operation:
auto stride = [](int n) {
return [s = -1, n](auto const&) mutable { s = (s + 1) % n; return !s; };
};
All in all, the final solution looks like this:
auto even_teens = std::views::iota(0, 100)
| std::views::drop_while([](int i) { return i < 10; })
| std::views::take_while([](int i) { return i < 20; })
| std::views::filter(stride(2));
Code on Wandbox
Suppose
b = ["good ", "bad "]
a = ["apple","mango"]
then output = ["good apple","good mango","bad apple","bad mango"]
I know this can be done with nested for loops but is there some elegant one liner for doing this using C++ STL?
Here is a one-liner (copied from Jonathan Mee's answer posted here):
for(size_t i = 0, s = a.size(); i < output.size(); ++i) output[i] = b[i/s] + ' ' + a[i%s];
Full example here.
Given vector<string> a and vector<string> b you can use for_each:
vector<string> output(size(a) * size(b));
for_each(begin(output), end(output), [&, it = 0U](auto& i) mutable {
i = a[it / size(b)] + ' ' + b[it % size(b)];
++it;
});
Live Example
EDIT:
We've initialized output with enough room to contain every combination of a and b. Then we'll step through each element of output and assign it.
We'll want to use the 1st element of a for the first size(b) elements of output, and the 2nd element of a for the second size(b) elements, and so on. So we'll do this by indexing with it / size(b). We'll want to combine that by iteration through b's elements.
it will move to the next index for each element of output but the indexing needs to wrap or it will be out of bounds when it == size(b), to do that we use it % size(b).
EDIT2:
In this question through benchmarking I'd discovered the phenomenon that modulo and division are expensive operations for iteration. I've done the same test here. For the purpose of isolating the algorithms I'm just doing the Cartesian summation on a vector<int> not vector<string>.
First off we can see the two algorithms result in differing assembly. My algorithm as written above requires 585 lines of assembly. 588 lines were required by my interpretation of MSalter's code
vector<string> output(size(testValues1) * size(testValues2));
auto i = begin(output);
std::for_each(cbegin(a), cend(a), [&](const auto& A) { std::for_each(cbegin(b), cend(b), [&](const auto& B) { *i++ = A + ' ' + B; }); });
I have placed a pretty solid benchmarking test here: http://ideone.com/1YpzIO In the test I've only got it set to do 100 tests yet MSalters' algorithm always wins. Locally using Visual Studio 2015 in release with 10,000,000 tests MSalters algorithm finishes in about 2/3 the time it takes mine.
Clearly modulo isn't a great method of indexing :(
There's no direct solution; I checked the whole of <algorithm>. None of the functions produce an output of length M*N.
What you can do is call std::for_each on the first range, using a lambda which calls std::for_each on the second range (!)
std::vector<std::string> a, b;
std::for_each(a.begin(), a.end(),
[&](std::string A) { std::for_each(b.begin(), b.end(),
[A](std::string B) { std::cout << A << '/' << B << '\n'; }
);});
But that's just a nested loop in STL.
I have a vector a storing values [0 1 2 3 5] and other vector removelist storing the indexes to be removed [0 1 2] in order to leave [3 5] at the end. When I'm implementing the following code, it would remove items unexpectedly since the vector a will be changing order during the process. Is there any way for me to achieve my target?
for (int i = 0; i<removelist.size() ; i++)
a.erase(a.begin() + removelist[i]);
Reverse the order you remove values, i.e. use the reverse iterators of removelist. This of course relies on removelist being sorted.
Perhaps something like
std::sort(removelist.begin(), removelist.end()); // Make sure the container is sorted
for (auto &i = removelist.rbegin(); i != removelist.rend(); ++ i)
{
a.erase(a.begin() + *i);
}
Not necessarily more efficient, but you can do this without sorting using remove_if:
auto& rm = removelist; // for brevity
a.erase(remove_if(begin(a), end(a), [&](int i) {
auto idx = distance(begin(v), find(begin(v), end(v), i));
return find(begin(rm), end(rm), idx) != end(rm);
}, end(a));
The solution to this is to copy the elements you want to keep to a new vector:
// pseudocode:
vector tmp;
tmp.reserve(a.size() - removelist.size());
for (i=0; i<a.size(); ++i) {
if (i not in removelist) {
tmp.push_back(a[i]);
}
}
a.swap(tmp);
Notes:
You have to make sure that the indices are unique, otherwise the preallocation fails.
This avoids various reallocations using the preallocated, temporary vector. The reallocations of a also avoid the index shift in your approach.
If the elements in removelst are sorted, this can be implemented a bit more efficiently.
I wonder where that list comes from. Can't you remove the elements on the fly instead of creating a temporary list?
Adapted from #Yam Marcovic's answer, not using find but use the exact address to find the index:
a.erase(std::remove_if(a.begin(), a.end(), [&](const int& i) {
auto idx = ((void*)&i - (void*)&*a.begin());
return std::find(removelist.begin(), removelist.end(), idx) != removelist.end();
}), a.end());
This is not similar to Can you remove elements from a std::list while iterating through it?. Mine is a different scenario.
Lets say I have a list like this.
1 2 3 1 2 2 1 3
I want to iterate this stl list in such a way that
When I first encounter an element X I do some activity and then I need to remove all the elements X in that list and continue iterating. Whats an efficient way of doing this in c++.
I am worried that when i do a remove or an erase I will be invalidating the iterators. If it was only one element then I could potentially increment the iterator and then erase. But in my scenario I would need to delete/erase all the occurances.
Was thinking something like this
while (!list.empty()) {
int num = list.front();
// Do some activity and if successfull
list.remove(num);
}
Dont know if this is the best.
Save a set of seen numbers and if you encounter a number in the set ignore it. You can do as follows:
list<int> old_list = {1, 2, 3, 1, 2, 2, 1, 3};
list<int> new_list;
set<int> seen_elements;
for(int el : old_list) {
if (seen_elements.find(el) == seen_elements.end()) {
seen_elements.insert(el);
new_list.push_back(el);
}
}
return new_list;
This will process each value only once and the new_list will only contain the first copy of each element in the old_list. This runs in O(n*log(n)) because each iteration performs a set lookup (you can make this O(n) by using a hashset). This is significantly better than the O(n^2) that your approach runs in.
I'm trying to iterate a vector from the nth element onwards. Not sure how should i go about doing this.
I have a vector A and B. My vector A has 10 elements of PC1-PC10 and my vector B has 20 elements of User1-User20.
So what I want to do is that when both my vector A and B reaches the 10th element, meaning to say the last element for vector A, I want to repeat iterating vector A but start iterating vector B from the 11th element so that I can do some stuff with it.
Below is the simplified code that I came up with but technically its about the same thing:
vector<string>::iterator b = vecB.begin();
for (int i = 1; i < 2; i++) {
for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; a++) {
if (a == vecA.end()) {
b = vecB.begin() + 10; //here the iterator for verB should start from the 11th element
}
++b
}
}
Should I mess with the iterator for vector B? Or is there another alternative?
EDIT
It seems that I have been asking the wrong question after all. I have marked the answer to this question and will be posting another shortly. Thanks for the quick response to my question!
The if condition inside the nested loop will never be true, because it conflicts with the loop condition:
for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; a++) {
// This check ----------------------------------^^^^^^^^^^^^^^^
// guarantees that this will never succeed:
// vvvvvvvvvvvvvvv
if (a == vecA.end()) {
...
}
}
You should rewrite the code like this:
vector<string>::iterator b = vecB.begin();
// Check that vecB has sufficient number of elements before entering the loop.
for (int i = 1 ; i < 2 ; i++) {
for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; ++a, ++b) {
...
}
// At this point we know for sure that a == vecA.end(),
// because it is a post-condition of the for loop above.
b = std::next(vecB.begin(), 11);
}
The call of ++b can be moved into the loop header.
Note the use of std::next: although
b = vecB.begin() + 10;
compiles for vectors, it is not guaranteed for all kinds of containers. Use std::next instead:
b = std::next(vecB.begin(), 11);
Note: This code makes an assumption that vecB has at least 11 elements more than vecA does. This may be OK if you check that assumption before entering the loop. If this assumption is broken, the code would have undefined behavior.
Others have already answered how to reset or advance an iterator, so I'll just answer, how to solve your problem in a simpler way. It's much simpler to iterate two vectors in parallel using the index rather than two iterators:
// assumes vecB is bigger than vecA as described in the question
for (std::size_t i = 0; i < vecB.size(); i++) {
auto user = vecB[i];
auto pc = vecA[i % vecA.size()];
}
Pay attention to how the smaller vector is iterated using the remainder operator.
In addition to using std::next, as shown in the answer by #dasblinkenlight, you can also use std::advance.
b = vecB.begin();
std::advance(b, 10);
You don't need to change the iterator for B, it will automatically continue with 11th element. But you need to restart iteration on A at the beginning of the for loop (or you would work with a.end() which is not a valid element):
if (a == vecA.end()) {
a = vecA.begin();
}
Also you should iterate over both but check for end on b only; if you check on a, the for would end before the if would turn true:
for (auto a = vecA.begin(), b = vecB.begin(); b != vecB.end(); ++a, ++b)
You can see the whole code here.
I actually prefer to manually iterate over vectors pre-C++11 because it looks way cleaner and more readable than iterators:
for (unsigned int i = 0; i < my_vector.size(); i++) {
my_vector[i]; //Do Something
}
You can specify the range you want to iterate over simply by modifying the for loop conditional (i.e. unsigned int i = n)
Edit: Before downvoting actually read my entire answer. Using iterators on vectors is overly verbose and makes your code virtually unreadable. If there is a legitimate reason this method should not be used in favor of iterators, then please leave a comment.
Most people aren't looking for an ultra-generic, drop-in-any-container solution. Most people know they need a dynamic list, vector fits the bill, so why not make your code easy to read for the next guy?