Передайте дополнительные аргументы в remove_if

Я хотел бы удалить элементы из вектора, используя 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 ...

7

Решение

Состояние, указывающее, «сколько элементов было удалено до сих пор», должно быть определено вне функции / вызова алгоритма. Это потому, что у функтора не должно быть состояния, которое изменяется при вызове (это было бы неопределенным поведением).

Вы должны взять ссылку на это состояние (счетчик) в конструкторе функтора (или захватить по ссылке в лямбде), чтобы вы могли получить доступ и изменить этот счетчик. Когда этот функтор теперь копируется, не имеет значения, какой из них вызывается алгоритмом, поскольку все они теперь содержат ссылку на то же состояние.

Использование функторов (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));

Использование лямбды (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());
11

Другие решения

Помимо создания собственного функтора, вы можете передать лямбда-выражение:

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());

Однако остерегайтесь того, что функторы с сохранением состояния и алгоритмы библиотеки std не всегда хорошо сочетаются. Здесь, звонки в лямбду могут иметь побочный эффект, поэтому у вас нет гарантии на который элементы в последовательности будут удалены.

Обратите внимание на последний звонок std::vector::erase, Это необходимо для того, чтобы действительно удалить ненужные элементы из контейнера. Увидеть стереть удалить идиома.

4

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) } );
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());
2

Код в проголосовавшем ответе имеет небольшую ошибку. Перед ключевым словом оператора отсутствуют круглые скобки. Я не мог сделать правку, поскольку в ней меньше шести символов, и я не мог комментировать, так как мой счет слишком низкий.

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));
2
По вопросам рекламы [email protected]