En std :: multiset, ¿hay una función o algoritmo para borrar solo una muestra (unicada o duplicada) si se encuentra un elemento?

83

Tal vez esto es un duplicado, pero no encontré nada de búsqueda: Cuando erase(value)se pidió a std::multisettodos los elementos con el valor encontrado se eliminan. La única solución que se me ocurre es:

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

Esto está bien, pero pensé que podría haber algo mejor. Algunas ideas ?

Martín
fuente
22
Este es un enfoque perfectamente razonable.
templatetypedef
¿Este enfoque asegura que la clave dada ("5") esté duplicada?
Arun
@ArunSaha: No. Pero si no es un duplicado, quiero eliminarlo de todos modos. Por las respuestas que obtuve, tengo la sensación de que no hay mejor solución. Quizás la pregunta fue estúpida en primer lugar :-P
Martin
1
Por multimap: ¿hay alguna garantía sobre qué elementos finddevuelve? (¿Orden de inserción? ¿Incluso después de tal borrado? ¿Depende de la implementación?)
P Marecki
2
Honestamente, es un error tan obvio al usar multiset que no se encuentra entre las clases más utilizadas.
Predelnik

Respuestas:

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

Me imagino que hay una forma más limpia de lograr lo mismo. Pero esto hace el trabajo.

user2251346
fuente
7
Esto no es diferente a lo que está en la pregunta.
Trovador
1
¡Estoy de acuerdo! No tiene ningún sentido. Otras 12 personas vieron algo útil en la respuesta, así que sé que no me estoy volviendo loco.
user2251346
6
Nunca
pase por
15

Prueba este:

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

Siempre que pueda asegurarse de que las valuesalidas en el conjunto. Eso funciona.

Extraño
fuente
2
 if(my_multiset.find(key)!=my_multiset.end())
   my_multiset.erase(my_multiset.equal_range(key).first);

Esta es la mejor manera que se me ocurre de eliminar una sola instancia en un conjunto múltiple en c ++

varun kunchakuri
fuente
1
En comparación con la solución que propuse en la pregunta, su código hace dos búsquedas (buscar + rango_igual) en lugar de una que es ineficiente
Martin
como esta es la misma complejidad, me gusta mucho esta respuesta. Gracias
Crystal
1

Intentaría lo siguiente.

Primera llamada equal_range()para encontrar el rango de elementos que igualan a la clave.

Si el rango devuelto no está vacío, entonces erase()un rango de elementos (es decir, el erase()que toma dos iteradores) donde:

  • el primer argumento es el iterador del segundo elemento en el rango devuelto (es decir, un pasado .firstdevuelto) y

  • el segundo argumento como el del iterador del par de rango devuelto .second.


Edite después de leer el comentario de templatetypedef (¡Gracias!):

Si se supone que se elimina un duplicado (a diferencia de todos): si el par devuelto por equal_range()tiene al menos dos elementos, entonces erase()el primer elemento pasa el .first del par devuelto a la versión de iterador único de erase():

Pseudocódigo:

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

if( distance( pit.first, pit.second ) >= 2 ) {
    mymultiset.erase( pit.first );
}
Arun
fuente
2
Creo que la pregunta es sobre eliminar solo un duplicado, no todos los duplicados.
templatetypedef
¿Tiene una idea de si esto es más rápido que mi solución y, si es así, por qué?
Martin
1

Esto funcionó para mí:

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

si val existe en el multi-set.

Yukty
fuente
0

Podemos hacer algo como esto:

multiset<int>::iterator it, it1;
it = myset.find(value);
it1 = it;
it1++;
myset.erase (it, it1);
Dipen Dadhaniya
fuente
1
Exageración. "Iterador que apunta a un único elemento que se eliminará de unordered_multiset".
Andrew
-3

De hecho, la respuesta correcta es:

my_multiset.erase(my_multiset.find(value));
usuario3075328
fuente
1
Si el valor no existe en el multiset, provoca un comportamiento indefinido .
kien_coi_1997