В std :: multiset есть функция или алгоритм для удаления только одного образца (однозначного или повторяющегося), если элемент найден


83

Возможно, это дубликат, но я ничего не нашел поиском: При erase(value)вызове std::multisetвсе элементы с найденным значением удаляются. Единственное решение, которое я мог придумать, это:

std::multiset<int>::iterator hit(mySet.find(5));
if (hit!= mySet.end()) mySet.erase(hit);

Это нормально, но я подумал, что может быть лучше. Есть идеи ?


22
Это вполне разумный подход.
templatetypedef

Гарантирует ли этот подход дублирование данного ключа («5»)?
Арун,

@ArunSaha: Нет. Но если это не дубликат, я все равно хочу его удалить. Судя по полученным ответам, я чувствую, что лучшего решения нет. Может быть, вопрос изначально был дурацким :-P
Мартин

1
Для multimap: есть ли гарантия, какие элементы findвозвращаются? (Порядок вставки? Даже после такого стирания? Зависит от реализации?)
P Marecki

2
Честно говоря, это такая неочевидная ошибка при использовании мультимножества, которое не входит в число наиболее часто используемых классов.
Пределник

Ответы:


31
auto itr = my_multiset.find(value);
if(itr!=my_multiset.end()){
    my_multiset.erase(itr);
}

Я полагаю, что есть более чистый способ сделать то же самое. Но это делает свою работу.


10
Это не отличается от того, о чем идет речь.
Трубадур

2
Я согласен! В этом нет никакого смысла. Еще 12 человек увидели в ответе что-то полезное, поэтому я знаю, что не сойду с ума.
user2251346 04

8
Никогда не
упускайте

16

Попробуй это:

multiset<int> s;
s.erase(s.lower_bound(value));

Пока вы можете убедиться, что valueвыходы в комплекте. Это работает.


2
 if(my_multiset.find(key)!=my_multiset.end())
   my_multiset.erase(my_multiset.equal_range(key).first);

Это лучший способ, который я могу придумать, чтобы удалить один экземпляр в мультимножестве в c ++


1
По сравнению с решением, которое я предложил в вопросе, ваш код выполняет два поиска (find + equal_range) вместо одного, который неэффективен
Мартин

так как это такая же сложность, мне очень нравится этот ответ. Спасибо
Crystal

1

Я бы попробовал следующее.

Сначала вызовите, equal_range()чтобы найти диапазон элементов, равных ключу.

Если возвращаемый диапазон непустой, тогда erase()диапазон элементов (то есть, erase()который принимает два итератора), где:

  • первый аргумент - это итератор для 2-го элемента в возвращаемом диапазоне (т.е. .firstвозвращенный один прошлый ) и

  • второй аргумент как итератор возвращаемой пары диапазонов .second.


Отредактируйте после прочтения комментария templatetypedef (спасибо!):

Если один (а не все) дубликат предполагается удалить: если пара, возвращаемая с помощью, equal_range()имеет по крайней мере два элемента, то erase()первый элемент путем передачи .first из возвращенной пары в версию с одним итератором erase():

Псевдокод:

pair<iterator, iterator> pit = mymultiset.equal_range( key );

if( distance( pit.first, pit.second ) >= 2 ) {
    mymultiset.erase( pit.first );
}

2
Я думаю, что вопрос заключается в том, чтобы удалить только один дубликат, а не все дубликаты.
templatetypedef

Есть идеи, быстрее ли это моего решения, и если да, то почему?
Мартин

1

Это сработало для меня:

multi_set.erase(multi_set.find(val));

если val существует в мультинаборе.


0

Мы можем сделать что-то вроде этого:

multiset<int>::iterator it, it1;
it = myset.find(value);
it1 = it;
it1++;
myset.erase (it, it1);

1
Перебор. «Итератор, указывающий на единственный элемент, который нужно удалить из unordered_multiset.»
Эндрю

0
 auto itr=ms.find(value);  
  while(*itr==value){
  ms.erase(value);
  itr=ms.find(value);  
  }

Попробуйте этот. Он удалит все дубликаты, доступные в мультимножестве.


-3

На самом деле правильный ответ:

my_multiset.erase(my_multiset.find(value));

1
Если значение не существует в мультимножестве, это вызывает неопределенное поведение .
kien_coi_1997
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.