Suppose I want to remove items according to some criterium. Let's say:
假设我要根据一些标准来移除项。比方说:
QMap<int, int> map;
and I want to remove all the items where value is an odd number. If I use an iterator:
我想要移除所有的项,其中值是一个奇数。如果我使用迭代器:
for (auto it = map.begin(); it != map.end(); ++it)
if (it.value() % 2 == 1)
map.remove(it.key());
This code is probably wrong, since the call of
这段代码可能是错误的,因为调用了
map.remove(it.key())
invalidates the iterator. How can I do this without reseting the iterator after each removal?
迭代器将会失效。如何在每次删除之后不重新设置迭代器呢?
2 个解决方案
#1
17
Use QMap::erase
instead, which returns an iterator to the element following the one you just erased:
使用QMap:::擦除,它返回一个迭代器到元素的后面,紧跟着刚才擦除的元素:
for (auto it = map.begin(); it != map.end();)
if (it.value() % 2 == 1)
it = map.erase(it);
else
++it;
Another way is to use the postfix increment operator on the iterator:
另一种方法是在迭代器上使用后缀递增运算符:
for (auto it = map.begin(); it != map.end();)
if (it.value() % 2 == 1)
map.erase(it++);
else
++it;
Yet another way (and probably less efficient) is to use the STL remove_copy_if
algorithm, followed by swap
:
另一种方法(可能效率更低)是使用STL remove_copy_if算法,然后是swap:
bool valueIsOdd(int value) {return value % 2 == 1;}
QMap<int,int> b;
std::remove_copy_if(a.begin(), a.end(),
std::inserter(b, b.end()),
&valueIsOdd);
a.swap(b);
I cannot test the last example at the moment.
我现在不能测试最后一个例子。
#2
4
You would be better off using the more STL-like erase
function:
你最好使用更像stl的擦除功能:
- It takes an iterator as an argument, and so doesn't waste time searching for the element by its key when you already know where it is;
- 它使用迭代器作为参数,因此,当您已经知道它的位置时,它不会浪费时间搜索元素;
- It returns an iterator to the next element, so you can carry on iterating afterwards.
- 它将迭代器返回到下一个元素,因此您可以在之后进行迭代。
Using this, you can implement your loop correctly as:
使用此方法,您可以正确地实现循环,如:
for (auto it = map.begin(); it != map.end(); /* don't increment here */) {
if (it.value() % 2 == 1) {
it = map.erase(it);
} else {
++it;
}
}
I think you could get the same result from map.remove((it++).key())
, but that would be both slower and messier than erase
.
我认为从map.remove((it+).key() .key())中可以得到相同的结果,但是这比erase要慢得多,也更混乱。
#1
17
Use QMap::erase
instead, which returns an iterator to the element following the one you just erased:
使用QMap:::擦除,它返回一个迭代器到元素的后面,紧跟着刚才擦除的元素:
for (auto it = map.begin(); it != map.end();)
if (it.value() % 2 == 1)
it = map.erase(it);
else
++it;
Another way is to use the postfix increment operator on the iterator:
另一种方法是在迭代器上使用后缀递增运算符:
for (auto it = map.begin(); it != map.end();)
if (it.value() % 2 == 1)
map.erase(it++);
else
++it;
Yet another way (and probably less efficient) is to use the STL remove_copy_if
algorithm, followed by swap
:
另一种方法(可能效率更低)是使用STL remove_copy_if算法,然后是swap:
bool valueIsOdd(int value) {return value % 2 == 1;}
QMap<int,int> b;
std::remove_copy_if(a.begin(), a.end(),
std::inserter(b, b.end()),
&valueIsOdd);
a.swap(b);
I cannot test the last example at the moment.
我现在不能测试最后一个例子。
#2
4
You would be better off using the more STL-like erase
function:
你最好使用更像stl的擦除功能:
- It takes an iterator as an argument, and so doesn't waste time searching for the element by its key when you already know where it is;
- 它使用迭代器作为参数,因此,当您已经知道它的位置时,它不会浪费时间搜索元素;
- It returns an iterator to the next element, so you can carry on iterating afterwards.
- 它将迭代器返回到下一个元素,因此您可以在之后进行迭代。
Using this, you can implement your loop correctly as:
使用此方法,您可以正确地实现循环,如:
for (auto it = map.begin(); it != map.end(); /* don't increment here */) {
if (it.value() % 2 == 1) {
it = map.erase(it);
} else {
++it;
}
}
I think you could get the same result from map.remove((it++).key())
, but that would be both slower and messier than erase
.
我认为从map.remove((it+).key() .key())中可以得到相同的结果,但是这比erase要慢得多,也更混乱。