c++ 删除循环内的向量元素

dvtswwa3  于 2021-06-23  发布在  其他
关注(0)|答案(7)|浏览(170)

我知道有类似的问题,但我没有设法找到我的代码的帮助下的方式。我只想删除/删除一个向量的元素,通过检查这个元素在一个循环内的属性。我该怎么做呢?我尝试了下面的代码,但我收到了模糊的错误消息:
"operator ="函数在"播放器"中不可用。

for (vector<Player>::iterator it = allPlayers.begin(); it != allPlayers.end(); it++)
 {
     if(it->getpMoney()<=0) 
         it = allPlayers.erase(it);
     else 
         ++it;
 }

我该怎么办?

zzzyeukh

zzzyeukh1#

您不应在for循环中递增it

for (vector<Player>::iterator it=allPlayers.begin(); 
                              it!=allPlayers.end(); 
                              /*it++*/) <----------- I commented it.
{

   if(it->getpMoney()<=0) 
      it = allPlayers.erase(it);
  else 
      ++it;
 }

注意注解部分;这里不需要it++,因为it在for-body本身中递增。
关于错误“'operator =' function is available in 'Player'",这是由于使用了erase(),内部使用operator=来移动vector中的元素,为了使用erase(),类Player的对象必须是可赋值的,这意味着需要为Player类实现operator=
无论如何,你应该尽可能地避免raw loop 1,而应该更喜欢使用算法来代替,在这种情况下,流行的Erase-Remove Idiom可以简化你正在做的事情。

allPlayers.erase(
    std::remove_if(
        allPlayers.begin(), 
        allPlayers.end(),
        [](Player const & p) { return p.getpMoney() <= 0; }
    ), 
    allPlayers.end()
);

1.这是我看过的the best talks by Sean Parent之一。

amrnrhlw

amrnrhlw2#

if(allPlayers.empty() == false) {
    for(int i = allPlayers.size() - 1; i >= 0; i--) {
        if(allPlayers.at(i).getpMoney() <= 0) {
            allPlayers.erase( allPlayers.begin() + i ); 
        }
    }
}

这是我删除向量中元素的方法,简单易懂,不需要任何技巧。

to94eoyn

to94eoyn3#

忘记循环,使用标准或升压范围算法。
使用Boost.Range en Lambda,它看起来像这样:

boost::remove_if( allPlayers, bind(&Player::getpMoney, _1)<=0 );
b4qexyjb

b4qexyjb4#

您的特定问题是Player类没有赋值运算符。您必须使"Player"可复制或可移动才能将其从向量中删除。这是因为该向量需要连续,因此需要重新排序元素以填充删除元素时产生的间隙。
还有:
使用标准算法

allPlayers.erase(std::remove_if(allPlayers.begin(), allPlayers.end(), [](const Player& player)
{
    return player.getpMoney() <= 0;
}), allPlayers.end());

如果你有boost的话就更简单了

boost::remove_erase_if(allPlayers, [](const Player& player)
{
    return player.getpMoney() <= 0;
});

如果您不支持C++11 lambdas,请参阅TimW的答案。

jucafojl

jucafojl5#

或者倒着做。

for (vector<Player>::iterator it = allPlayers.end() - 1; it != allPlayers.begin() - 1; it--)
    if(it->getpMoney()<=0) 
        it = allPlayers.erase(it);
ogq8wdun

ogq8wdun6#

C++11引入了一个新的函数集合,在这里会用到。

allPlayers.erase(
    std::remove_if(allPlayers.begin(), allPlayers.end(),
        [](auto& x) {return x->getpMoney() <= 0;} ), 
    allPlayers.end());

这样你就得到了一个好处,那就是不需要对末端元素做太多的移动。

zi8p0yeb

zi8p0yeb7#

回答晚,但已看到低效变体:

  1. std::removestd::remove_if是要走的路。
    1.如果出于任何原因,这些是不可用的,或者因为任何其他原因而不能被使用,那么做这些对你隐藏的事情。
    有效删除元素的代码:
auto pos = container.begin();
for(auto i = container.begin(); i != container.end(); ++i)
{
    if(isKeepElement(*i)) // whatever condition...
    {
        if(i != pos)
        {
            *pos = *i; // will move, if move assignment is available...
        }
        ++pos;
    }
}
// well, std::remove(_if) stops here...
container.erase(pos, container.end());

您可能需要显式地编写这样的循环,例如,如果您需要迭代器本身来确定元素是否要被删除(条件参数需要接受对元素的引用,还记得吗?),例如,由于与后继者/前导者的特定关系(如果这种关系是相等的,那么存在std::unique)。

相关问题