我想使用remove_if
函数从矢量中删除元素,但将删除限制为N个元素。
示例:
// predicate function that determines if a value is an odd number.
bool IsOdd (int i) {
if (we deleted more than deleteLimit)
return false;
return ((i%2)==1);
}
void otherFunc(){
int deleteLimit = 10;
// remove odd numbers:
std::vector<int>::iterator newEnd =
std::remove_if (myints.begin(), myints.end(), IsOdd (how to pass deleteLimit?) );
}
我需要IsOdd
谓词存储已移除的元素数量以及我们要删除的元素数量。
唯一的方法是使用全局变量?像这样:
int deleteLimit = 10;
int removedSoFar = 0;
bool IsOdd (int i) {
if (deleteLimit < removedSoFar)
return false;
if (i%2==1) {
removedSoFar++
return true;
}
return false;
}
remove_if ...
答案 0 :(得分:11)
应该在函数/对算法的调用之外定义告诉“到目前为止已删除了多少元素”的状态。这是因为仿函数不应该具有在被调用时被修改的状态(这将是未定义的行为)。
您应该在仿函数的构造函数中引用此状态(计数器)(或通过lambda中的引用捕获),以便您可以访问和修改此计数器。现在复制这个仿函数时,算法调用哪个仿函数并不重要,因为它们现在都拥有对相同状态的引用。
使用仿函数(C ++ 03):
class IsOdd {
int deleteLimit;
int & deletedSoFar;
public:
IsOdd(int deleteLimit, int & deletedSoFar) :
deleteLimit(deleteLimit), deletedSoFar(deletedSoFar)
{}
bool operator()(int i) const {
if (deletedSoFar < deleteLimit && i % 2) {
++deletedSoFar;
return true;
}
return false;
}
};
int deletedSoFar = 0;
int deleteLimit = 10;
std::remove_if (myints.begin(), myints.end(), IsOdd(deleteLimit, deletedSoFar));
使用lambda(C ++ 11):
int deletedSoFar = 0;
int deleteLimit = 10;
auto it = std::remove_if (myints.begin(), myints.end(), [deleteLimit,&deletedSoFar](int i){
if (deletedSoFar < deleteLimit && i % 2) {
++deletedSoFar;
return true;
}
return false;
});
myints.erase(it, myints.end());
答案 1 :(得分:4)
除了创建自己的仿函数外,还可以传递lambda表达式:
auto deleteLimit = 25;
auto removedSoFar = 0;
auto it = remove_if (myints.begin(),
myints.end(),
[deleteLimit, &removedSoFar](int i)->bool
{
if ( (deletedSoFar < deleteLimit) && (i % 2)) {
++deletedSoFar;
return true;
}
return false;
} );
// really remove the elements from the container
myints.erase(it, myints.end());
但是,请注意stateful functors and std library algorithms are not always good mix。在这里,对lambda的调用可能会产生副作用,因此您无法保证将删除序列中的元素。
请注意std::vector::erase
的最终通话。这是真正从容器中删除不需要的元素所必需的。请参阅erase remove idiom。
答案 2 :(得分:2)
使用functor
,结构operator ()
,或使用一些绑定功能(std :: bind / boost :: bind)。
bool isOdd(int current, int limit, int& count)
{
if (count >= limit)
{
return false;
}
if (current % 2 == 1)
{
++count;
return true;
}
return false;
}
int count = 0, limit = 10;
vec.erase(std::remove_if(vec.begin(), vec.end(),
std::bind(&isOdd, _1, limit, std::ref(count)), vec.end());
使用仿函数
struct IsOdd : public std::unary_function<int, bool>
{
public:
IsOdd(int l) : count(0), limit(l)
{
}
bool operator () (int i)
{
if (count >= limit)
{
return false;
}
if (current % 2 == 1)
{
++count;
return true;
}
return false;
private:
int count;
int limit;
};
int limit = 10;
vec.erase(std::remove_if(vec.begin(), vec.end(),
isOdd(limit)), vec.end());
答案 3 :(得分:2)
int initial_size = myints.size();
std::remove_if (myints.begin(), myints.end(), [myints.size(),limit,initial_size](int i)->bool{
return ( ( initial_size-myints.size() )<limit ? i%2 : false) } );
答案 4 :(得分:2)
投票答案中的代码有一个小错误。在operator关键字之前缺少括号。我无法将编辑作为少于六个字符,因为我的分数太低,我无法发表评论。
class IsOdd {
int deleteLimit;
int & deletedSoFar;
public:
IsOdd(int deleteLimit, int & deletedSoFar) :
deleteLimit(deleteLimit), deletedSoFar(deletedSoFar)
{}
bool operator()(int i) const {
if (deletedSoFar < deleteLimit && i % 2) {
++deletedSoFar;
return true;
}
return false;
}
};
int deletedSoFar = 0;
int deleteLimit = 10;
std::remove_if (myints.begin(), myints.end(), IsOdd(deleteLimit, deletedSoFar));