C++ 删除循环内向量的元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8628951/
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
Remove elements of a vector inside the loop
提问by arjacsoh
I know that there are similar questions to this one, but I didn't manage to find the way on my code by their aid. I want merely to delete/remove an element of a vector by checking an attribute of this element inside a loop. How can I do that? I tried the following code but I receive the vague message of error:
我知道有与此类似的问题,但我没有通过他们的帮助找到我的代码的方法。我只想通过检查循环内此元素的属性来删除/删除向量的元素。我怎样才能做到这一点?我尝试了以下代码,但收到了模糊的错误消息:
'operator =' function is unavailable in 'Player'.
'operator =' 功能在 'Player' 中不可用。
for (vector<Player>::iterator it = allPlayers.begin(); it != allPlayers.end(); it++)
{
if(it->getpMoney()<=0)
it = allPlayers.erase(it);
else
++it;
}
What should I do?
我该怎么办?
Update:Do you think that the question vector::erase with pointer memberpertains to the same problem? Do I need hence an assignment operator? Why?
更新:您是否认为带有指针成员的问题vector::erase 与同一问题有关?因此我需要赋值运算符吗?为什么?
回答by Nawaz
You should not increment it
in the for
loop:
你不应该it
在for
循环中递增:
for (vector<Player>::iterator it=allPlayers.begin();
it!=allPlayers.end();
/*it++*/) <----------- I commented it.
{
if(it->getpMoney()<=0)
it = allPlayers.erase(it);
else
++it;
}
Notice the commented part;it++
is not needed there, as it
is getting incremented in the for-body itself.
注意注释部分;it++
那里不需要,因为it
在 for-body 本身中增加了。
As for the error "'operator =' function is unavailable in 'Player'", it comes from the usage of erase()
which internally uses operator=
to move elements in the vector. In order to use erase()
, the objects of class Player
must be assignable, which means you need to implement operator=
for Player
class.
至于错误“ 'operator =' function is not available in 'Player'”,则是由于使用了erase()
它内部用于operator=
移动向量中的元素。为了使用erase()
,类的对象Player
必须是可分配的,这意味着您需要operator=
为Player
类实现。
Anyway, you should avoid raw loop1as much as possible and should prefer to use algorithms instead. In this case, the popular Erase-Remove Idiomcan simplify what you're doing.
无论如何,您应该尽可能避免使用原始循环1,而应该更喜欢使用算法。在这种情况下,流行的Erase-Remove Idiom可以简化您的操作。
allPlayers.erase(
std::remove_if(
allPlayers.begin(),
allPlayers.end(),
[](Player const & p) { return p.getpMoney() <= 0; }
),
allPlayers.end()
);
1. It's one of the best talks by Sean Parentthat I've ever watched.
1. 这是我看过的最好的 Sean Parent 演讲之一。
回答by Dawoon Yi
if(allPlayers.empty() == false) {
for(int i = allPlayers.size() - 1; i >= 0; i--) {
if(allPlayers.at(i).getpMoney() <= 0) {
allPlayers.erase( allPlayers.begin() + i );
}
}
}
This is my way to remove elements in vector. It's easy to understand and doesn't need any tricks.
这是我删除向量中元素的方法。它很容易理解,不需要任何技巧。
回答by TimW
Forget the loop and use the std or boost range algorthims.
Using Boost.Range en Lambda it would look like this:
忘记循环并使用 std 或 boost 范围算法。
使用 Boost.Range en Lambda 它看起来像这样:
boost::remove_if( allPlayers, bind(&Player::getpMoney, _1)<=0 );
回答by ronag
Your specific problem is that your Player
class does not have an assignment operator. You must make "Player" either copyable or movable in order to remove it from a vector. This is due to that vector needs to be contiguous and therefore needs to reorder elements in order to fill gaps created when you remove elements.
您的具体问题是您的Player
班级没有赋值运算符。您必须使“播放器”可复制或可移动才能将其从向量中删除。这是因为该向量需要是连续的,因此需要对元素重新排序以填充删除元素时创建的空白。
Also:
还:
Use std algorithm
使用标准算法
allPlayers.erase(std::remove_if(allPlayers.begin(), allPlayers.end(), [](const Player& player)
{
return player.getpMoney() <= 0;
}), allPlayers.end());
or even simpler if you have boost:
如果你有提升,甚至更简单:
boost::remove_erase_if(allPlayers, [](const Player& player)
{
return player.getpMoney() <= 0;
});
See TimW's answer if you don't have support for C++11 lambdas.
如果您不支持 C++11 lambda,请参阅 TimW 的回答。
回答by hhhhhhhhh
Or do the loop backwards.
或者向后循环。
for (vector<Player>::iterator it = allPlayers.end() - 1; it != allPlayers.begin() - 1; it--)
if(it->getpMoney()<=0)
it = allPlayers.erase(it);
回答by UKMonkey
C++11 has introduced a new collection of functions that will be of use here.
C++11 引入了一个新的函数集合,在这里会用到。
allPlayers.erase(
std::remove_if(allPlayers.begin(), allPlayers.end(),
[](auto& x) {return x->getpMoney() <= 0;} ),
allPlayers.end());
And then you get the advantage of not having to do quite so much shifting of end elements.
然后您将获得不必对终端元素进行太多移动的优势。
回答by Aconcagua
Late answer, but as having seen inefficient variants:
迟到的答案,但看到效率低下的变体:
std::remove
orstd::remove_if
is the way to go.- If for any reason those are not available or cannot be used for whatever other reason, do what these hide away from you.
std::remove
或者std::remove_if
是要走的路。- 如果出于任何原因这些不可用或因任何其他原因不能使用,请执行这些隐藏的操作。
Code for removing elements efficiently:
有效删除元素的代码:
auto pos = container.begin();
for(auto i = container.begin(); i != container.end(); ++i)
{
if(isKeepElement(*i)) // whatever condition...
{
*pos++ = *i; // will move, if move assignment is available...
}
}
// well, std::remove(_if) stops here...
container.erase(pos, container.end());
You might need to write such a loop explicitly e. g. if you need the iterator itself to determine if the element is to be removed (the condition parameter needs to accept a reference to element, remember?), e. g. due to specific relationship to successor/predecessor (if this relationship is equality, though, there is std::unique
).
您可能需要明确地编写这样一个循环,例如,如果您需要迭代器本身来确定是否要删除元素(条件参数需要接受对元素的引用,还记得吗?),例如由于与后继/前驱的特定关系(但是,如果这种关系是平等的,则存在std::unique
)。