In my code I used an array, I decided to try std :: set. I did this with an array:
for (int i=0; i<100; i++)
{
drawNMS(true, myMassive[myStr+i]);
}
myStr is added by buttons.
For std :: set, as I understand it, I need to use an iterator.
I try to do so:
std::set <int>::iterator iter;
for(iter=mySet.begin(); iter!=mySet.end();iter++)
{
drawNMS(true, myStr+*iter);
}
Where to insert for (int i = 0; i <100; i ++) correctly so that the end result is like when working with an array?
If you want to iterate over first 100 elements of a set, then do this:
std::set <int>::iterator iter;
int counter = 0;
for(iter=mySet.begin(); iter!=mySet.end() && counter < 100;++iter, ++counter)
{
drawNMS(true, myStr+*iter);
}
If you can use C++20, there is std::ranges which provides std::ranges::advance that works with a boundary, so your end-iterator can be found like this (not tested):
auto endSet100 = std::ranges::advance(mySet.begin(), 100, mySet.end());
This end-iterator can then be used like the original end-iterator. If you use std::advance, you have to do the boundary check yourself and the advance works on the iterator itself without returning a new iterator.
For simpler looping:
for (const auto& elem: std::ranges::subrange(mySet.begin(), std::ranges::advance(mySet.begin(), 100, mySet.end()))
{
drawNMS(true, myStr+elem);
}
It may be a bit longer, but it states: loop a subrange from the beginning to the 100th element or all if less elements are present.
Related
I have a vector that holds items that are either active or inactive. I want the size of this vector to stay small for performance issues, so I want items that have been marked inactive to be erased from the vector. I tried doing this while iterating but I am getting the error "vector iterators incompatible".
vector<Orb>::iterator i = orbsList.begin();
while(i != orbsList.end()) {
bool isActive = (*i).active;
if(!isActive) {
orbsList.erase(i++);
}
else {
// do something with *i
++i;
}
}
The most readable way I've done this in the past is to use std::vector::erase combined with std::remove_if. In the example below, I use this combination to remove any number less than 10 from a vector.
(For non-c++0x, you can just replace the lambda below with your own predicate:)
// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));
// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(),
[](int i) { return i < 10; }), v.end());
I agree with wilx's answer. Here is an implementation:
// curFiles is: vector < string > curFiles;
vector< string >::iterator it = curFiles.begin();
while(it != curFiles.end()) {
if(aConditionIsMet) {
it = curFiles.erase(it);
}
else ++it;
}
You can do that but you will have to reshuffle your while() a bit, I think. The erase() function returns an iterator to the element next after the erased one: iterator erase(iterator position);. Quoting from the standard from 23.1.1/7:
The iterator returned from a.erase(q)
points to the element immediately
following q prior to the element being
erased. If no such element exists,
a.end() is returned.
Though maybe you should be using the Erase-remove idiom instead.
erase returns a pointer to the next iterator value (same as Vassilis):
vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{ if(condition)
mit = myVec.erase(mit);
else
mit++;
}
If someone need working on indexes
vector<int> vector;
for(int i=0;i<10;++i)vector.push_back(i);
int size = vector.size();
for (int i = 0; i < size; ++i)
{
assert(i > -1 && i < (int)vector.size());
if(vector[i] % 3 == 0)
{
printf("Removing %d, %d\n",vector[i],i);
vector.erase(vector.begin() + i);
}
if (size != (int)vector.size())
{
--i;
size = vector.size();
printf("Go back %d\n",size);
}
}
As they said, vector's iterators get invalidated on vector::erase() no matter which form of iterator increment you use. Use an integer index instead.
You might want to consider using a std::list instead of a std::vector for your data structure. It is safer (less bug prone) to use when combining erasure with iteration.
Removing items from the middle of a vector will invalidate all iterators to that vector, so you cannot do this (update: without resorting to Wilx's suggestion).
Also, if you're worried about performance, erasing items from the middle of a vector is a bad idea anyway. Perhaps you want to use an std::list?
I have a vector that holds items that are either active or inactive. I want the size of this vector to stay small for performance issues, so I want items that have been marked inactive to be erased from the vector. I tried doing this while iterating but I am getting the error "vector iterators incompatible".
vector<Orb>::iterator i = orbsList.begin();
while(i != orbsList.end()) {
bool isActive = (*i).active;
if(!isActive) {
orbsList.erase(i++);
}
else {
// do something with *i
++i;
}
}
The most readable way I've done this in the past is to use std::vector::erase combined with std::remove_if. In the example below, I use this combination to remove any number less than 10 from a vector.
(For non-c++0x, you can just replace the lambda below with your own predicate:)
// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));
// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(),
[](int i) { return i < 10; }), v.end());
I agree with wilx's answer. Here is an implementation:
// curFiles is: vector < string > curFiles;
vector< string >::iterator it = curFiles.begin();
while(it != curFiles.end()) {
if(aConditionIsMet) {
it = curFiles.erase(it);
}
else ++it;
}
You can do that but you will have to reshuffle your while() a bit, I think. The erase() function returns an iterator to the element next after the erased one: iterator erase(iterator position);. Quoting from the standard from 23.1.1/7:
The iterator returned from a.erase(q)
points to the element immediately
following q prior to the element being
erased. If no such element exists,
a.end() is returned.
Though maybe you should be using the Erase-remove idiom instead.
erase returns a pointer to the next iterator value (same as Vassilis):
vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{ if(condition)
mit = myVec.erase(mit);
else
mit++;
}
If someone need working on indexes
vector<int> vector;
for(int i=0;i<10;++i)vector.push_back(i);
int size = vector.size();
for (int i = 0; i < size; ++i)
{
assert(i > -1 && i < (int)vector.size());
if(vector[i] % 3 == 0)
{
printf("Removing %d, %d\n",vector[i],i);
vector.erase(vector.begin() + i);
}
if (size != (int)vector.size())
{
--i;
size = vector.size();
printf("Go back %d\n",size);
}
}
As they said, vector's iterators get invalidated on vector::erase() no matter which form of iterator increment you use. Use an integer index instead.
You might want to consider using a std::list instead of a std::vector for your data structure. It is safer (less bug prone) to use when combining erasure with iteration.
Removing items from the middle of a vector will invalidate all iterators to that vector, so you cannot do this (update: without resorting to Wilx's suggestion).
Also, if you're worried about performance, erasing items from the middle of a vector is a bad idea anyway. Perhaps you want to use an std::list?
How to get int position of this loop? Thank you.
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (; a != vect.end() && b != vect2.end() && c != vect3.end(); a++, b++, c++) {
}
I need to print values of other variable, but I need to get actual unsigned int position of this vector loop.
I need to print double vector using this position of this vector.
And how to get the last index of vector.
My problem is for for loop with multiple vectors and getting index from it next to use only last of indexes.
As Angew shows, a simple indexed loop may be preferable when you need indices.
However, it is possible to get the index from an iterator as well:
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (/*the loop conditions*/) {
auto index = a - vect.begin();
}
It is also possible to get the index of a forward iterator using std::distance, but it would be unwise to use it in a loop, since the complexity will be linear for non-random-access iterators.
In the case of forward iterators (and generic code that must support forward iterators), you can write a loop which has both the index variable, and the iterators.
P.S. it is potentially preferable to use pre-increment with iterators. Probably only matters in debug build.
It's simple: if you need indices, don't use iterators:
for (
size_t idx = 0, idxEnd = std::min({vect.size(), vect2.size(), vect3.size()});
idx < idxEnd;
++idx
)
{
auto& obj1 = vect[idx];
auto& obj2 = vect2[idx];
auto& obj3 = vect3[idx];
}
(The above code initialises idxEnd once at the start of the loop, so that it's not needlessly recomputed at each iteration. It's just an optimisation).
I have two equal length vectors from which I want to remove elements based on a condition in one of the vectors. The same removal operation should be applied to both so that the indices match.
I have come up with a solution using std::erase, but it is extremely slow:
vector<myClass> a = ...;
vector<otherClass> b = ...;
assert(a.size() == b.size());
for(size_t i=0; i<a.size(); i++)
{
if( !a[i].alive() )
{
a.erase(a.begin() + i);
b.erase(b.begin() + i);
i--;
}
}
Is there a way that I can do this more efficiently and preferably using stl algorithms?
If order doesn't matter you could swap the elements to the back of the vector and pop them.
for(size_t i=0; i<a.size();)
{
if( !a[i].alive() )
{
std::swap(a[i], a.back());
a.pop_back();
std::swap(b[i], b.back());
b.pop_back();
}
else
++i;
}
If you have to maintain the order you could use std::remove_if. See this answer how to get the index of the dereferenced element in the remove predicate:
a.erase(remove_if(begin(a), end(a),
[b&](const myClass& d) { return b[&d - &*begin(a)].alive(); }),
end(a));
b.erase(remove_if(begin(b), end(b),
[](const otherClass& d) { return d.alive(); }),
end(b));
The reason it's slow is probably due to the O(n^2) complexity. Why not use list instead? As making a pair of a and b is a good idea too.
A quick win would be to run the loop backwards: i.e. start at the end of the vector. This tends to minimise the number of backward shifts due to element removal.
Another approach would be to consider std::vector<std::unique_ptr<myClass>> etc.: then you'll be essentially moving pointers rather than values.
I propose you create 2 new vectors, reserve memory and swap vectors content in the end.
vector<myClass> a = ...;
vector<otherClass> b = ...;
vector<myClass> new_a;
vector<myClass> new_b;
new_a.reserve(a.size());
new_b.reserve(b.size());
assert(a.size() == b.size());
for(size_t i=0; i<a.size(); i++)
{
if( a[i].alive() )
{
new_a.push_back(a[i]);
new_b.push_back(b[i]);
}
}
swap(a, new_a);
swap(b, new_b);
It can be memory consumed, but should work fast.
erasing from the middle of a vector is slow due to it needing to reshuffle everything after the deletion point. consider using another container instead that makes erasing quicker. It depends on your use cases, will you be iterating often? does the data need to be in order? If you aren't iterating often, consider a list. if you need to maintain order, consider a set. if you are iterating often and need to maintain order, depending on the number of elements, it may be quicker to push back all alive elements to a new vector and set a/b to point to that instead.
Also, since the data is intrinsically linked, it seems to make sense to have just one vector containing data a and b in a pair or small struct.
For performance reason need to use next.
Use
vector<pair<myClass, otherClass>>
as say #Basheba and std::sort.
Use special form of std::sort with comparision predicate. And do not enumerate from 0 to n. Use std::lower_bound instead, becouse vector will be sorted. Insertion of element do like say CashCow in this question: "how do you insert the value in a sorted vector?"
I had a similar problem where I had two :
std::<Eigen::Vector3d> points;
std::<Eigen::Vector3d> colors;
for 3D pointclouds in Open3D and after removing the floor, I wanted to delete all points and colors if the points' z coordinate is greater than 0.05. I ended up overwriting the points based on the index and resizing the vector afterward.
bool invert = true;
std::vector<bool> mask = std::vector<bool>(points.size(), invert);
size_t pos = 0;
for (auto & point : points) {
if (point(2) < CONSTANTS::FLOOR_HEIGHT) {
mask.at(pos) = false;
}
++pos;
}
size_t counter = 0;
for (size_t i = 0; i < points.size(); i++) {
if (mask[i]) {
points.at(counter) = points.at(i);
colors.at(counter) = colors.at(i);
++counter;
}
}
points.resize(counter);
colors.resize(counter);
This maintains order and at least in my case, worked almost twice as fast than the remove_if method from the accepted answer:
for 921600 points the runtimes were:
33 ms for the accepted answer
17 ms for this approach.
What I have is a vector of elements, I do not care about the order of them.
Than I have N indexes (each addressing unique position in the vector) of elements to be removed from the vector. I want the removal be as fast as possible.
Best I could come up with was to store indexes in set (order indexes):
std::set<unsigned int> idxs;
for (int i=0; i<N; ++i)
idxs.insert(some_index);
And than iterating over the set in reversed order and replacing index to remove by last element of the vector.
std::set<unsigned int>::reverse_iterator rit;
for (rit = idxs.rbegin(); rit != idxs.rend(); ++rit) {
vec[*rit].swap(vec[vec.size() - 1]);
vec.resize(vec.size() - 1);
}
However I was thinking whether there is some more efficient way of doing this since the usage of set seems a bit overkill to me and I would love to avoid sorting at all.
EDIT1:
Let us assume I use vector and sort it afterwards.
std::vector<unsigned int> idxs;
for (int i=0; i<N; ++i)
idxs.push_back(some_index);
std::sort(idxs.begin(), idxs.end());
Can I push it any further?
EDIT2:
I should have mentioned that the vector will have up to 10 elements. However the removal in my program occurs very often (hundreds of thousands times).
set is a good choice. I'd guess using another allocator (e.g. arena)would have the biggest impact. Why not use a set instead of a vector of elements to begin with?
I see the following relevant variations:
Instead of remove, create a new vector and copy preserved elements, then swap back.
This keeps your indices stable (unlike removal, which would require sorting or updating the indices).
Instead of a vector of indices, use a vector of bools of the same length as your data.
With the length of "maximum 10" given, a bit mask seems sufficient
So, roughly:
struct Index
{
DWORD removeMask = 0; // or use bit vector for larger N
void TagForRemove(int idx) { removeMask |= (1<<idx); }
boll DoRemove(int idx) const { return (removeMask & (1<<idx)) != 0; }
}
// create new vector, or remove, as you like
void ApplyRemoveIndex(vector<T> & v, Index remove)
{
vector<T> copy;
copy.reserve(v.size());
for (i=0..v.size())
if (!remove.DoRemove(i))
copy.push_back(v[i]);
copy.swap(v);
}
You can use swap/pop_back to remove an item at a given index, and keep track of which indices you've moved with a hash table. It's linear space & time in the number of removals.
std::vector<T> vec = ...;
std::vector<unsigned int> idxs;
std::unordered_map<unsigned int, unsigned int> map;
for(auto index : idxs) {
unsigned int trueIndex = index;
while (trueIndex >= vec.size()) {
trueIndex = map[trueIndex];
}
// element at index 'vec.size()-1' is being moved to index 'index'
map[vec.size()-1] = index;
swap(vec[trueIndex], vec[vec.size()-1]);
vec.pop_back();
}