remove также имеет несколько вариантов. Что, если требуется удалить элементы, которые удовлетворяют некоторому предикату, а не просто равны какому-то значению? Используйте remove_if. Например, представьте, что есть класс с именем Conn, который представляет какой-то тип соединений. Если это соединение простаивает больше определенного значения, его требуется удалить. Во-первых, создайте функтор, как здесь.
struct IdleConnFn :
public std::unary_function
bool operator() (const Conn& c) const { // чтобы он работал с
if (с.getIdleTime() > TIMEOUT) { // другими объектами из
return(true); //
} else return(false);
}
} idle;
Затем вызовите remove_if с erase и передайте в него новый функтор, как здесь.
vec.erase(std::remove_if(vec.begin(), vec.end(), idle), vec.end());
Есть причина, по которой такие функторы следует наследовать от unary_function, unary_function определяет несколько typedef, используемых другими функторами из , и если они их не найдут, то другие функторы не скомпилируются. Например, если вы очень злы и хотите удалить все не задействованные в данный момент соединения, то в функторе проверки на простой можно использовать функтор not1.
vec.erase(std::remove_if(vec.begin(), vec.end(); std::not1(idle)),
vec.end());
Наконец, вам может потребоваться сохранить первоначальную последовательность (может, с помощью const) и скопировать результаты, кроме некоторых элементов, в новую последовательность. Это можно сделать с помощью remove_copy и remove_copy_if, которые работают аналогично remove и remove_if, за исключением того, что здесь также требуется передавать iterator вывода, в который будут записываться результирующие данные. Например, чтобы скопировать из одного списка в другой строку, сделайте так.
std::remove_copy(lstStr.begin(), lstStr.end(), lstStr2, "cloudy");
При использовании remove_copy или любого стандартного алгоритма, записывающего в выходной диапазон, следует помнить, что выходной диапазон должен уже быть достаточно большим, чтобы в нем поместились элементы, которые туда будут записываться.
erase и remove (и связанные с ними алгоритмы) предлагают удобный способ удалять определенные элементы последовательностей. Они предоставляют простую альтернативу самостоятельному перебору и поиску нужных элементов с последующим их удалением по одному.
Рецепты 6.2 и 7.1.
7.3. Случайное перемешивание данных
Имеется последовательность данных и требуется перемешать их так, чтобы они были расположены в случайном порядке.
Используйте стандартный алгоритм random_shuffle, определенный в . random_shuffle принимает два итератора произвольного доступа и (необязательно) функтор генератора случайных чисел и реорганизует случайным образом элементы заданного диапазона. Пример 7.3 показывает, как это делается.
#include
#include
#include
#include
#include "utils.h" // Для printContainer(): см. 7.10
using namespace std;
int main() {
vector
back_insert_iterator
for (int i = 0; i < 10; ++i) *p = i;
printContainer(v, true);
random_shuffle(v.begin(), v.end());
printContainer(v, true);
}
Вывод должен выглядеть примерно так.
-----
0123456789
-----
8192057346
random_shuffle очень прост в использовании. Дайте ему диапазон, и он перемешает этот диапазон случайным образом. Имеется две версии, и их прототипы выглядят так.
void random_shuffle(RndIter first, RndIter last);
void random_shuffle(RndIter first, RndIter last, RandFunc& rand);
В первой версии используется зависящая от реализации функция генерации случайных чисел, которой должно быть достаточно для большинства задач. Если ее недостаточно — например, требуется неоднородное распределение, такое, как гауссово — то можно написать собственную функцию, которую можно передать во вторую версию.