Использование алгоритмов в multimap - C ++ [duplicate]

Вот еще один способ. Промежуточные переменные не сохраняются.

Мы использовали это для удаления дубликатов результатов из множества перекрывающихся запросов.

  $ input = array_map ("unserialize", array_unique (array_map ("serialize", $  вход)));   
96
задан aJ. 29 April 2009 в 06:05
поделиться

10 ответов

[D0] Почти.

for(; iter != endIter; ) { if (Some Condition) { aMap.erase(iter++); } else { ++iter; } }

То, что вы изначально могли бы увеличить итератор дважды, если вы удалили из него элемент; вы можете пропустить элементы, которые нужно удалить.

Это общий алгоритм, который я видел во многих местах и ​​документировал.

[EDIT] Вы правы, что итераторы недействительны после стирания, но только итераторы, ссылающиеся на стираемый элемент, остаются в силе иными итераторами. Следовательно, используя iter ++ в вызове erase ().

97
ответ дан Amnon 16 August 2018 в 05:39
поделиться
  • 1
    Я смущен; зачем вы использовали for (; ...;) вместо while (...)? Кроме того, хотя это, вероятно, работает, не делает .erase возвращать итератор следующего? Итак, кажется, что if (Some Condition) blog должен быть iter = aMap.erase (iter) самым совместимым. Может, я что-то упустил? Мне не хватает опыта, который у вас есть. – taxilian 20 February 2011 в 04:38
  • 2
    Обратите внимание, что в C ++ 11 все ассоциативные контейнеры, включая map, возвращают следующий итератор из erase(iter). Это сделать намного более чистым iter = erase( iter ). – Potatoswatter 21 June 2012 в 16:53
  • 3
    @taxilian (годы позже) while () или for () будут работать, но семантически люди часто используют for () для итерации по известному диапазону и while () для неизвестного числа циклов. Поскольку диапазон известен в этом случае (от начала до endIter ), для () не был бы необычным выбором и, вероятно, был бы более распространенным. Но опять же, оба были бы приемлемыми. – Jamin Grey 15 June 2013 в 23:45
  • 4
    @taxilian. Что еще более важно: с 'for' вы можете определить свое определение итератора INSIDE в области цикла, так что это не путается с остальной частью вашей программы. – Sanchises 18 June 2014 в 08:34
  • 5
    @athos Вопрос сформулирован в пассивном голосе, «рекомендуется». Нет универсальной рекомендации. Я думаю, что мой последний комментарий - самый простой способ. Он включает в себя две копии переменной итератора, которая теряет небольшую эффективность, как указал кто-то здесь. Это ваш звонок, что подходит вам. – Potatoswatter 6 June 2017 в 12:24

Я получил эту документацию из отличной ссылки SGI STL:

Карта имеет важное свойство, что вставка нового элемента в карту не делает недействительными итераторы, указывающие на существующие элементы. Стирание элемента с карты также не отменяет никаких итераторов, за исключением, конечно, для итераторов, которые фактически указывают на стираемый элемент.

Итак, итератор, который у вас есть, который указывает на стираемый элемент, конечно же, будет признан недействительным. Сделайте что-то вроде этого:

if (some condition) { iterator here=iter++; aMap.erase(here) }
2
ответ дан 1800 INFORMATION 16 August 2018 в 05:39
поделиться
  • 1
    Это не отличается от исходного кода. iter ++ увеличивает итератор, а затем возвращает итератор, указывающий на элемент до приращения. – Steve Folly 29 April 2009 в 06:52
  • 2
    Но iter не будет признан недействительным, так как тогда мы удалим его здесь – 1800 INFORMATION 29 April 2009 в 07:30
  • 3
    @ 1800INFORMATION: ввод вызова функции является точкой последовательности, побочный эффект приращения оценивается до вызова erase. Таким образом, они действительно эквивалентны. Тем не менее, я бы предпочел вашу версию над оригиналом. – peterchen 25 March 2015 в 12:20
  • 4
    Да, я думаю, ты прав – 1800 INFORMATION 25 March 2015 в 21:31

IMHO нет эквивалента remove_if(). Вы не можете изменить порядок карты. Таким образом, remove_if() не может поставить интересующие вас пары в конце, на которые вы можете позвонить erase().

1
ответ дан Alexis Wilke 16 August 2018 в 05:39
поделиться

Ответ от 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);
1
ответ дан Community 16 August 2018 в 05:39
поделиться
  • 1
    Это кажется неэффективным. – allyourcode 28 February 2014 в 00:59
  • 2
    "Идентификаторы, начинающиеся с символа подчеркивания, за которым следует буква верхнего регистра, зарезервированы для всего использования реализацией. & quot; – YSC 24 November 2017 в 10:40

Теперь std::experimental::erase_if доступен в заголовке <experimental/map>.

См. http://en.cppreference.com/w/cpp/experimental/map/erase_if

0
ответ дан Floern 16 August 2018 в 05:39
поделиться

erase_if для std :: map (и других контейнеров)

Для этого я использую следующий шаблон.

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 });
60
ответ дан Iron Savior 16 August 2018 в 05:39
поделиться
  • 1
    +1 Правильный ответ с правильным многоразовым кодом :) – CodeAngry 5 September 2013 в 08:57
  • 2
    @CodeAngry Спасибо - мне всегда казалось странным, что этого еще не было в std. Я понимаю, почему он не является членом std::map, но я думаю, что что-то вроде этого должно быть в стандартной библиотеке. – Iron Savior 17 December 2013 в 18:15

Исходный код имеет только одну проблему:

for(; iter != endIter; ++iter) { if(Some Condition) { // is it safe ? aMap.erase(iter++); } }

Здесь iter увеличивается один раз в цикле for и в другое время стирания, которое, вероятно, закончится в некотором бесконечном цикле. [ ! d1]

2
ответ дан Kate Gregory 16 August 2018 в 05:39
поделиться

Из нижних нот:

http://www.sgi.com/tech/stl/PairAssociativeContainer.html

Пара ассоциативный контейнер не может предоставлять изменяемые итераторы (как определенные в требованиях тривиального итератора), поскольку тип значения изменяемого итератора должен быть назначаемым, а пара не назначаема. Однако ассоциативный контейнер пары может предоставить итераторы, которые не являются полностью постоянными: итераторы, для которых справедливо выражение (* i) .second = d.

1
ответ дан piotr 16 August 2018 в 05:39
поделиться

Если вы хотите стереть все элементы с ключом больше 2, лучший способ -

map.erase(map.upper_bound(2), map.end());

Работает только для диапазонов, но не для какого-либо предиката.

0
ответ дан Tadeusz Kopec 16 August 2018 в 05:39
поделиться

Первая

Карта имеет важное свойство, что вставка нового элемента в карту не делает недействительными итераторы, указывающие на существующие элементы. Стирание элемента с карты также не отменяет никаких итераторов, за исключением, конечно, для итераторов, которые фактически указывают на стираемый элемент.

Во-вторых, следующий код хорош

for(; iter != endIter; ) { if(Some Condition) { aMap.erase(iter++); } else { ++iter; } }

При вызове функции параметры оцениваются перед вызовом этой функции.

Итак, когда iter ++ оценивается перед вызовом для удаления, оператор итератора ++ возвращает текущий элемент и будет указывать на следующий элемент после вызова.

1
ответ дан Vincent 16 August 2018 в 05:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: