c++ - clase - ¿Cómo comprobar que un elemento está en un std:: set?
std set count (9)
// Sintaxis general
set<int>::iterator ii = find(set1.begin(),set1.end(),"element to be searched");
/ * en el siguiente código estoy intentando encontrar el elemento 4 y el conjunto int si está presente o no * /
set<int>::iterator ii = find(set1.begin(),set1.end(),4);
if(ii!=set1.end())
{
cout<<"element found";
set1.erase(ii);// in case you want to erase that element from set.
}
¿Cómo verificas que un elemento está en un conjunto?
¿Existe un equivalente más simple del siguiente código:
myset.find(x) != myset.end()
Escribe lo tuyo:
template<class T>
bool checkElementIsInSet(const T& elem, const std::set<T>& container)
{
return container.find(elem) != container.end();
}
La forma típica de verificar la existencia en muchos contenedores STL es:
const bool is_in = container.find(element) != container.end();
Otra forma de decir simplemente si un elemento existe es verificar el count()
if (myset.count(x)) {
// x is in the set, count is 1
} else {
// count zero, i.e. x not in the set
}
La mayoría de las veces, sin embargo, me encuentro necesitando acceso al elemento donde verifico su existencia.
Así que tendría que encontrar el iterador de todos modos. Entonces, por supuesto, es mejor simplemente compararla para end
también.
set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
// do something with *it
}
Pude escribir una función general de contains
para std::list
y std::vector
,
template<typename T>
bool contains( const list<T>& container, const T& elt )
{
return find( container.begin(), container.end(), elt ) != container.end() ;
}
template<typename T>
bool contains( const vector<T>& container, const T& elt )
{
return find( container.begin(), container.end(), elt ) != container.end() ;
}
// use:
if( contains( yourList, itemInList ) ) // then do something
Esto limpia la sintaxis un poco.
Pero no pude usar la plantilla de plantilla de parámetros mágicos para hacer que esto funcione de forma arbitraria en contenedores STL.
// NOT WORKING:
template<template<class> class STLContainer, class T>
bool contains( STLContainer<T> container, T elt )
{
return find( container.begin(), container.end(), elt ) != container.end() ;
}
Cualquier comentario sobre mejorar la última respuesta sería bueno.
Si fueras a agregar una función contains
, podría verse así:
#include <algorithm>
#include <iterator>
template<class TInputIterator, class T> inline
bool contains(TInputIterator first, TInputIterator last, const T& value)
{
return std::find(first, last, value) != last;
}
template<class TContainer, class T> inline
bool contains(const TContainer& container, const T& value)
{
// This works with more containers but requires std::begin and std::end
// from C++0x, which you can get either:
// 1. By using a C++0x compiler or
// 2. Including the utility functions below.
return contains(std::begin(container), std::end(container), value);
// This works pre-C++0x (and without the utility functions below, but doesn''t
// work for fixed-length arrays.
//return contains(container.begin(), container.end(), value);
}
template<class T> inline
bool contains(const std::set<T>& container, const T& value)
{
return container.find(value) != container.end();
}
Esto funciona con std::set
, otros contenedores STL e incluso matrices de longitud fija:
void test()
{
std::set<int> set;
set.insert(1);
set.insert(4);
assert(!contains(set, 3));
int set2[] = { 1, 2, 3 };
assert(contains(set2, 3));
}
Editar:
Como se señaló en los comentarios, involuntariamente usé una función nueva en C ++ 0x ( std::begin
y std::end
). Aquí está la implementación casi trivial de VS2010:
namespace std {
template<class _Container> inline
typename _Container::iterator begin(_Container& _Cont)
{ // get beginning of sequence
return (_Cont.begin());
}
template<class _Container> inline
typename _Container::const_iterator begin(const _Container& _Cont)
{ // get beginning of sequence
return (_Cont.begin());
}
template<class _Container> inline
typename _Container::iterator end(_Container& _Cont)
{ // get end of sequence
return (_Cont.end());
}
template<class _Container> inline
typename _Container::const_iterator end(const _Container& _Cont)
{ // get end of sequence
return (_Cont.end());
}
template<class _Ty,
size_t _Size> inline
_Ty *begin(_Ty (&_Array)[_Size])
{ // get beginning of array
return (&_Array[0]);
}
template<class _Ty,
size_t _Size> inline
_Ty *end(_Ty (&_Array)[_Size])
{ // get end of array
return (&_Array[0] + _Size);
}
}
Solo para aclarar, la razón por la cual no hay ningún miembro similar a los contains()
en estos tipos de contenedores es porque le abriría la posibilidad de escribir un código ineficiente. Tal método probablemente solo haría un this->find(key) != this->end()
internamente, pero considera lo que haces cuando la clave está realmente presente; en la mayoría de los casos, querrá obtener el elemento y hacer algo con él. Esto significa que tendrías que hacer una segunda find()
, que es ineficiente. Es mejor usar find directamente, para que pueda almacenar en caché el resultado, así:
Container::const_iterator it = myContainer.find(key);
if (it != myContainer.end())
{
// Do something with it, no more lookup needed.
}
else
{
// Key was not present.
}
Por supuesto, si no le importa la eficiencia, siempre puede hacer su propio rollo, pero en ese caso probablemente no debería usar C ++ ...;)
También puede verificar si un elemento está en conjunto o no al insertar el elemento. La versión de un solo elemento devuelve un par, con su par de miembros :: primer conjunto a un iterador que apunta al elemento recién insertado o al elemento equivalente que ya está en el conjunto. El par :: segundo elemento del par se establece en verdadero si se insertó un nuevo elemento o falso si ya existía un elemento equivalente.
Por ejemplo: Supongamos que el conjunto ya tiene 20 como elemento.
std::set<int> myset;
std::set<int>::iterator it;
std::pair<std::set<int>::iterator,bool> ret;
ret=myset.insert(20);
if(ret.second==false)
{
//do nothing
}
else
{
//do something
}
it=ret.first //points to element 20 already in set.
Si el elemento se inserta nuevamente, pair :: first apuntará a la posición del nuevo elemento en conjunto.
yo suelo
if(!my_set.count(that_element)) //Element is present...
;
Pero no es tan eficiente como
if(my_set.find(that_element)!=my_set.end()) ....;
Mi versión solo ahorra tiempo al escribir el código. Lo prefiero así para la codificación competitiva.