Вот еще один способ. Промежуточные переменные не сохраняются.
Мы использовали это для удаления дубликатов результатов из множества перекрывающихся запросов.
$ input = array_map ("unserialize", array_unique (array_map ("serialize", $ вход)));
for(; iter != endIter; ) {
if (Some Condition) {
aMap.erase(iter++);
} else {
++iter;
}
}
То, что вы изначально могли бы увеличить итератор дважды, если вы удалили из него элемент; вы можете пропустить элементы, которые нужно удалить.
Это общий алгоритм, который я видел во многих местах и документировал.
[EDIT] Вы правы, что итераторы недействительны после стирания, но только итераторы, ссылающиеся на стираемый элемент, остаются в силе иными итераторами. Следовательно, используя iter ++ в вызове erase ().
Я получил эту документацию из отличной ссылки SGI STL:
Карта имеет важное свойство, что вставка нового элемента в карту не делает недействительными итераторы, указывающие на существующие элементы. Стирание элемента с карты также не отменяет никаких итераторов, за исключением, конечно, для итераторов, которые фактически указывают на стираемый элемент.Итак, итератор, который у вас есть, который указывает на стираемый элемент, конечно же, будет признан недействительным. Сделайте что-то вроде этого:
if (some condition)
{
iterator here=iter++;
aMap.erase(here)
}
IMHO нет эквивалента remove_if(). Вы не можете изменить порядок карты. Таким образом, remove_if() не может поставить интересующие вас пары в конце, на которые вы можете позвонить erase().
Ответ от Steve Folly Я чувствую себя более эффективным.
Вот еще одно легкое и менее эффективное решение:
В решении используется remove_copy_if для копирования значений, которые мы хотим в новый контейнер, затем меняет содержимое исходного контейнера на содержимое нового:
std::map<int, std::string> aMap;
...
//Temporary map to hold the unremoved elements
std::map<int, std::string> aTempMap;
//copy unremoved values from aMap to aTempMap
std::remove_copy_if(aMap.begin(), aMap.end(),
inserter(aTempMap, aTempMap.end()),
predicate);
//Swap the contents of aMap and aTempMap
aMap.swap(aTempMap);
Теперь std::experimental::erase_if доступен в заголовке <experimental/map>.
См. http://en.cppreference.com/w/cpp/experimental/map/erase_if
Для этого я использую следующий шаблон.
namespace stuff {
template< typename ContainerT, typename PredicateT >
void erase_if( ContainerT& items, const PredicateT& predicate ) {
for( auto it = items.begin(); it != items.end(); ) {
if( predicate(*it) ) it = items.erase(it);
else ++it;
}
};
}
Это ничего не вернет, но это удалит элементы из std :: map.
Пример использования:
// 'container' could be a std::map
// 'item_type' is what you might store in your container
using stuff::erase_if;
erase_if(container, []( item_type& item ) {
return /* insert appropriate test */;
});
Второй пример (позволяет передать тестовое значение):
// 'test_value' is value that you might inject into your predicate.
// 'property' is just used to provide a stand-in test
using stuff::erase_if;
int test_value = 4; // or use whatever appropriate type and value
erase_if(container, [&test_value]( item_type& item ) {
return item.property < test_value; // or whatever appropriate test
});
Исходный код имеет только одну проблему:
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
Здесь iter увеличивается один раз в цикле for и в другое время стирания, которое, вероятно, закончится в некотором бесконечном цикле. [ ! d1]
Из нижних нот:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
Пара ассоциативный контейнер не может предоставлять изменяемые итераторы (как определенные в требованиях тривиального итератора), поскольку тип значения изменяемого итератора должен быть назначаемым, а пара не назначаема. Однако ассоциативный контейнер пары может предоставить итераторы, которые не являются полностью постоянными: итераторы, для которых справедливо выражение (* i) .second = d.
Если вы хотите стереть все элементы с ключом больше 2, лучший способ -
map.erase(map.upper_bound(2), map.end());
Работает только для диапазонов, но не для какого-либо предиката.
Первая
Карта имеет важное свойство, что вставка нового элемента в карту не делает недействительными итераторы, указывающие на существующие элементы. Стирание элемента с карты также не отменяет никаких итераторов, за исключением, конечно, для итераторов, которые фактически указывают на стираемый элемент.Во-вторых, следующий код хорош
for(; iter != endIter; )
{
if(Some Condition)
{
aMap.erase(iter++);
}
else
{
++iter;
}
}
При вызове функции параметры оцениваются перед вызовом этой функции.
Итак, когда iter ++ оценивается перед вызовом для удаления, оператор итератора ++ возвращает текущий элемент и будет указывать на следующий элемент после вызова.