C++ std::remove_if - lambda,不从集合中删除任何内容
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4478636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
std::remove_if - lambda, not removing anything from the collection
提问by Robinson
Ok, I expect I've made a dumb mistake here. I have a list of DisplayDevice3d and each DisplayDevice3d contains a list of DisplayMode3d. I want to remove all items from the list of DisplayDevice3d that don't have any DisplayMode3d's. I'm trying to use a Lambda to do it, ie.:
好吧,我想我在这里犯了一个愚蠢的错误。我有一个 DisplayDevice3d 列表,每个 DisplayDevice3d 都包含一个 DisplayMode3d 列表。我想从 DisplayDevice3d 列表中删除所有没有任何 DisplayMode3d 的项目。我正在尝试使用 Lambda 来做到这一点,即:
// If the device doesn't have any modes, remove it.
std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(),
[](DisplayDevice3d& device)
{
return device.Modes.size() == 0;
}
);
Even though out of 6 DisplayMode3d's in MyDisplayDevices, only 1 has any DisplayMode3d's in its Modes collection, nothing is being removed from the list.
尽管在 MyDisplayDevices 中的 6 个 DisplayMode3d 中,只有 1 个在其 Modes 集合中有任何 DisplayMode3d,但没有从列表中删除任何内容。
What numpty mistake have I made here?
我在这里犯了什么大错?
Edit:
编辑:
Ah ok, my mistake was I should be using MyDisplayDevices.remove_if instead of std::remove_if, however the answers below are correct for use of std::remove_if :p.
好吧,我的错误是我应该使用 MyDisplayDevices.remove_if 而不是 std::remove_if,但是下面的答案对于使用 std::remove_if :p 是正确的。
MyDisplayDevices.remove_if( [](DisplayDevice3d const & device)
{
return device.Modes.size() == 0;
});
回答by
You need to call erase on the iterator returned from remove_if, It should look something like this:
您需要对从 remove_if 返回的迭代器调用擦除,它应该如下所示:
auto new_end = std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(),
[](const DisplayDevice3d& device)
{ return device.Modes.size() == 0; });
MyDisplayDevices.erase(new_end, MyDisplayDevices.end());
回答by Asha
回答by Saurav Sahu
回答by bobobobo
As others have mentioned, there are ways to make it work. However my advice would be to completely avoid remove_ifand stick to a standard iterator-based removal instead. The idiom below works both for listand vectorand does not produce unexpected behavior.
正如其他人所提到的,有一些方法可以让它发挥作用。然而,我的建议是完全避免remove_if并坚持标准的基于迭代器的删除。下面的习语适用于list并且vector不会产生意外行为。
for( vector<TYPE>::iterator iter = vec.begin() ; iter != vec.end() ; )
if( iter->shouldRemove )
iter = vec.erase( iter ) ; // advances iter
else
++iter ; // don't remove
As the comments below mention, this method does have a higher cost than remove_ifwhen more than 1 element is removed.
正如下面的评论所提到的,这种方法的成本确实remove_if比删除 1 个以上元素时的成本更高。
remove_ifworks by copying elements from further ahead in the vector, and overwriting vectors that should be removed from the vector by the one immediately in front of it. For example: remove_if called on a vector to remove all 0 elements:
remove_if工作原理是从向量中更靠前的位置复制元素,并覆盖应该从向量中移除的向量。例如:在向量上调用 remove_if 以删除所有 0 元素:
0 1 1 0 1 0
results in:
结果是:
1 1 1 0 1 0
Notice how the vector isn't correct yet. That is because remove_ifreturns an iterator to the last valid element... it doesn't automatically resize the vector. You still need to call v.erase()on the iterator returned from your call to remove_if.
注意向量是如何不正确的。那是因为remove_if返回一个迭代器到最后一个有效元素......它不会自动调整向量的大小。您仍然需要调用v.erase()从调用返回的迭代器remove_if。
An example is below
下面是一个例子
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
void print( vector<int> &v )
{
for( int i : v )
printf( "%d ", i );
puts("");
}
int main()
{
vector<int> v = { 0, 1, 1, 0, 1, 0 };
print( v ); // 0 1 1 0 1 0
vector<int>::iterator it = remove_if( v.begin(), v.end(), [](int i){ return i == 0; } );
print( v ); // 1 1 1 0 1 0
v.erase( it, v.end() ); // actually cut out values not wanted in vector
print( v ); // 1 1 1 (correct)
}


