La única forma de ser más simple sería un predicado booleano: template <typename T> bool member (T const & item). Y eso se implementaría (debajo de las cubiertas) en términos de la línea sobre la que está preguntando.
Don Wakefield el
Respuestas:
399
La forma típica de comprobar la existencia en muchos contenedores STL, tales como std::map, std::set, ... es:
Esto es específico para conjuntos y mapas. vectores, listas, etc. no tienen una función de miembro de búsqueda
wilhelmtell
8
OMI usando count () es mejor porque es simplemente más corto y se convierte en bool como se señala en la respuesta de Pieter. No entiendo por qué esta respuesta fue aceptada y tantos puntos ...
Огњен Шобајић
44
En aras de la exhaustividad: vectores / listas pueden usar std :: encuentran: std::find(container.begin(), container.end(), element) != container.end(); O (N) el problema persiste, por supuesto ...
Aconcagua
10
@MichaelMathews Con su variante: primero if(container.find(foo) == container.end())debe hacer una búsqueda de árbol para encontrar el elemento; si no se encuentra, debe hacer una segunda búsqueda de árbol para encontrar la ubicación de inserción correcta. La variante original if(container.insert(foo).second) {...}tiene el encanto de que solo necesita una sola búsqueda de árbol ...
Aconcagua
23
hay un set.contains(x)que devuelve un bool en el estándar C ++ 20. No sé por qué nos ha llevado hasta 2020 introducir eso.
Gremwell
215
Otra forma de decir simplemente si existe un elemento 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}
Sin embargo, la mayoría de las veces me encuentro necesitando acceso al elemento donde sea que verifique su existencia.
Así que tendría que encontrar el iterador de todos modos. Entonces, por supuesto, es mejor simplemente compararlo endtambién.
set< X >::iterator it = myset.find(x);if(it != myset.end()){// do something with *it}
Tenga en cuenta que usar en count()lugar de find()nunca es mejor, pero potencialmente peor. Esto se debe a find()que volverá después de la primera coincidencia, count()siempre iterará sobre todos los elementos.
Frerich Raabe
34
@Frerich eso solo es relevante multisety multimappensé. Aún así es bueno señalar :)
Pieter
83
std :: set se implementa típicamente con una estructura de árbol ordenada, por lo que count () y find () tendrán O (logn). Ninguno de los dos iterará sobre todos los elementos del conjunto.
Alan
14
@FrerichRaabe - ¿Estás seguro? Dado que solo es posible setcontener un miembro que coincida, ¿no se implementaría la función de tal manera que se detenga después de localizar el primer elemento, en este caso, como señala Pieter? Respuesta útil en cualquier caso!
Dan Nissenbaum
14
@DanNissenbaum Sí, tiene toda la razón (y también lo son + Peter y + Alan): para std :: set, las dos funciones son equivalentes en términos de rendimiento. Entonces, aunque la primera parte de mi comentario ( count()nunca siendo más rápido que find()) todavía se mantiene, la segunda parte no es aplicable a std::set. Sin embargo, supongo que se puede hacer otro argumento a favor find(): es más expresivo, es decir, enfatiza que estás tratando de encontrar un elemento en lugar de contar el número de ocurrencias.
Frerich Raabe
42
Solo para aclarar, la razón por la que no hay ningún miembro como contains()en estos tipos de contenedores es porque te abriría a escribir código ineficiente. Tal método probablemente solo lo haría this->find(key) != this->end()internamente, pero considere lo que hace cuando la clave está realmente presente; en la mayoría de los casos, querrás obtener el elemento y hacer algo con él. Esto significa que tendría que hacer un segundo find(), lo cual es ineficiente. Es mejor usar find directamente, para que pueda almacenar en caché su resultado, así:
auto 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 te importa la eficiencia, siempre puedes rodar la tuya, pero en ese caso probablemente no deberías estar usando C ++ ...;)
¿Qué pasa con los conjuntos? Por lo general, ya tiene el elemento, pero solo quiere verificar si está dentro.
Elazar Leibovich
8
¿Tiene alguna referencia a si esta es la razón real por la que dicho método / función no está incluido en el stl, o es solo su conjetura?
Fabio A.
3
@FabioA. Es mi suposición educada.
Tim
1
@Adhemar, la consistencia no es exactamente el lado fuerte de STL ... ( list::remove, remove(makes_sense_only_for_vector, iterators)...)
Elazar Leibovich
3
No tiene sentido para mí no incluir una función porque alguien podría usarla incorrectamente si no supieran lo que estaban haciendo. La programación es para personas que pueden pensar por sí mismas y son responsables de su código y su rendimiento
Slawekwin
13
En C ++ 20 finalmente obtendremos el std::set::containsmétodo.
#include<iostream>#include<string>#include<set>int main(){
std::set<std::string> example ={"Do","not","panic","!!!"};if(example.contains("panic")){
std::cout <<"Found\n";}else{
std::cout <<"Not found\n";}}
Si fuera a agregar una containsfunción, podría verse así:
#include<algorithm>#include<iterator>template<classTInputIterator,class T>inlinebool contains(TInputIterator first,TInputIteratorlast,const T&value){return std::find(first,last,value)!=last;}template<classTContainer,class T>inlinebool contains(constTContainer& 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>inlinebool contains(const std::set<T>& container,const T&value){return container.find(value)!= container.end();}
Esto funciona con std::setotros contenedores STL e incluso con matrices de longitud fija:
Como se señaló en los comentarios, involuntariamente utilicé una función nueva en C ++ 0x ( std::beginy std::end). Aquí está la implementación casi trivial de VS2010:
namespace std {template<class_Container>inlinetypename_Container::iterator begin(_Container&_Cont){// get beginning of sequencereturn(_Cont.begin());}template<class_Container>inlinetypename_Container::const_iterator begin(const_Container&_Cont){// get beginning of sequencereturn(_Cont.begin());}template<class_Container>inlinetypename_Container::iterator end(_Container&_Cont){// get end of sequencereturn(_Cont.end());}template<class_Container>inlinetypename_Container::const_iterator end(const_Container&_Cont){// get end of sequencereturn(_Cont.end());}template<class_Ty,size_t_Size>inline_Ty*begin(_Ty(&_Array)[_Size]){// get beginning of arrayreturn(&_Array[0]);}template<class_Ty,size_t_Size>inline_Ty*end(_Ty(&_Array)[_Size]){// get end of arrayreturn(&_Array[0]+_Size);}}
@Adhemar, en realidad fue ineficiente, pero no por la razón que mencionaste.
Sam Harwell el
@Paul: Asegúrate de incluir la especialización std::sety recuerda que solo es apropiado si lo único que necesitas saber es la existencia.
Sam Harwell el
@ 280Z28: std :: begin (container)? ¿Qué estándar STL es ese? No se compila en mi gcc.
stefaanv
@stefannv: je, es nuevo para C ++ 0x. Agregué la implementación de mi compilador anterior.
Sam Harwell el
2
@Adhemar: si sabe que el conjunto contiene un valor, entonces ya lo tiene. La única razón por la que necesitaría el iterador es para borrar el elemento del conjunto. Si todo lo que necesita es saber si una colección contiene o no un valor, entonces esta solución no es menos eficiente que cualquier otra solución.
Sam Harwell el
4
También puede verificar si un elemento está configurado o no mientras inserta el elemento. La versión de elemento único devuelve un par, con su par miembro :: primero configurado en 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 el conjunto.
acabo de hacerlo: template <class T> static inline bool contiene (const std :: set <T> & S, T x) {return (S.find (x)! = S.end ()); }
fulmicoton
44
@paul no crea funciones globales estáticas. coloque su función en un espacio de nombres anónimo: esa es la forma en C ++ de crear funciones que no se vincularán a otras unidades de compilación. Además, su parámetro T debe ser una referencia constante, para la corrección constante y para la eficiencia.
wilhelmtell
-1: Sin plantilla y en absoluto en estilo STL. Esto está bien si no está utilizando STL, pero si está utilizando STL, al menos debe intentar seguir sus estándares.
Sam Harwell el
1
@ 280Z28: Lamento que mi código no cumpla con sus estándares, solo estaba demostrando que si no le gusta la interfaz de STL, puede escribir la suya. Dios, no tentado? ¿Qué tan motivado tiene que ser? Su ejemplo se ve bien, eso no significa que el mío sea malo. Está más centrado en el set como lo solicitó el OP.
stefaanv
1
@ 280Z28: Estaba haciendo un punto. Pensé que las personas serían lo suficientemente inteligentes como para hacerse una idea.
stefaanv
2
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 me ahorra tiempo al escribir el código. Lo prefiero de esta manera para la codificación competitiva.
Sí, count(). Cualquiera que no pueda comprender que una función de retorno de enteros utilizada en una expresión booleana está probando un valor distinto de cero tendrá muchas, muchas otras tribulaciones en el gran mar de expresiones idiomáticas C / C ++. Y, como se señaló anteriormente, realmente debería ser tan eficiente para los conjuntos, que era la pregunta.
Ron Burk
0
Pude escribir una containsfunción general para std::listy std::vector,
Lo siento, no puedo escribir código de bloque en el comentario pero ¿qué pasa template<typename CONTAINER, typename CONTAINEE> bool contains(const CONTAINER& container, const CONTAINEE& needle) { return find(container.begin(), container.end(), needle) != container.end();
fulmicoton
No funciona, porque std :: vector necesita un asignador adicional como argumento de plantilla y std :: set necesita un asignador y un argumento de plantilla menos. Estas líneas funcionarían: template <template <class, class> class STLContainer, class T, class A> bool contiene (STLContainer <T, A> container, T elt) {return find (container.begin (), container.end ( ), elt)! = container.end (); } template <template <class, class, class> class STLContainer, class T, class L, class A> bool contiene (STLContainer <T, A, L> container, T elt) {return find (container.begin (), container .end (), elt)! = container.end (); }
tgmath
0
// Sintaxis general
set<int>::iterator ii = find(set1.begin(),set1.end(),"element to be searched");
/ * en el siguiente código, estoy tratando de encontrar el elemento 4 en int set 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.}
Respuestas:
La forma típica de comprobar la existencia en muchos contenedores STL, tales como
std::map
,std::set
, ... es:fuente
std::find(container.begin(), container.end(), element) != container.end()
; O (N) el problema persiste, por supuesto ...if(container.find(foo) == container.end())
debe hacer una búsqueda de árbol para encontrar el elemento; si no se encuentra, debe hacer una segunda búsqueda de árbol para encontrar la ubicación de inserción correcta. La variante originalif(container.insert(foo).second) {...}
tiene el encanto de que solo necesita una sola búsqueda de árbol ...set.contains(x)
que devuelve un bool en el estándar C ++ 20. No sé por qué nos ha llevado hasta 2020 introducir eso.Otra forma de decir simplemente si existe un elemento es verificar el
count()
Sin embargo, la mayoría de las veces me encuentro necesitando acceso al elemento donde sea que verifique su existencia.
Así que tendría que encontrar el iterador de todos modos. Entonces, por supuesto, es mejor simplemente compararlo
end
también.C ++ 20
En C ++ 20, el conjunto obtiene una
contains
función, por lo que lo siguiente se hace posible como se menciona en: https://stackoverflow.com/a/54197839/895245fuente
count()
lugar defind()
nunca es mejor, pero potencialmente peor. Esto se debe afind()
que volverá después de la primera coincidencia,count()
siempre iterará sobre todos los elementos.multiset
ymultimap
pensé. Aún así es bueno señalar :)set
contener un miembro que coincida, ¿no se implementaría la función de tal manera que se detenga después de localizar el primer elemento, en este caso, como señala Pieter? Respuesta útil en cualquier caso!count()
nunca siendo más rápido quefind()
) todavía se mantiene, la segunda parte no es aplicable astd::set
. Sin embargo, supongo que se puede hacer otro argumento a favorfind()
: es más expresivo, es decir, enfatiza que estás tratando de encontrar un elemento en lugar de contar el número de ocurrencias.Solo para aclarar, la razón por la que no hay ningún miembro como
contains()
en estos tipos de contenedores es porque te abriría a escribir código ineficiente. Tal método probablemente solo lo haríathis->find(key) != this->end()
internamente, pero considere lo que hace cuando la clave está realmente presente; en la mayoría de los casos, querrás obtener el elemento y hacer algo con él. Esto significa que tendría que hacer un segundofind()
, lo cual es ineficiente. Es mejor usar find directamente, para que pueda almacenar en caché su resultado, así:Por supuesto, si no te importa la eficiencia, siempre puedes rodar la tuya, pero en ese caso probablemente no deberías estar usando C ++ ...;)
fuente
list::remove
,remove(makes_sense_only_for_vector, iterators)
...)En C ++ 20 finalmente obtendremos el
std::set::contains
método.fuente
Si fuera a agregar una
contains
función, podría verse así:Esto funciona con
std::set
otros contenedores STL e incluso con matrices de longitud fija:Editar:
Como se señaló en los comentarios, involuntariamente utilicé una función nueva en C ++ 0x (
std::begin
ystd::end
). Aquí está la implementación casi trivial de VS2010:fuente
std::set
y recuerda que solo es apropiado si lo único que necesitas saber es la existencia.También puede verificar si un elemento está configurado o no mientras inserta el elemento. La versión de elemento único devuelve un par, con su par miembro :: primero configurado en 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.
Si el elemento se inserta nuevamente, pair :: first apuntará a la posición del nuevo elemento en el conjunto.
fuente
Escribe lo tuyo:
fuente
yo suelo
Pero no es tan eficiente como
Mi versión solo me ahorra tiempo al escribir el código. Lo prefiero de esta manera para la codificación competitiva.
fuente
count()
. Cualquiera que no pueda comprender que una función de retorno de enteros utilizada en una expresión booleana está probando un valor distinto de cero tendrá muchas, muchas otras tribulaciones en el gran mar de expresiones idiomáticas C / C ++. Y, como se señaló anteriormente, realmente debería ser tan eficiente para los conjuntos, que era la pregunta.Pude escribir una
contains
función general parastd::list
ystd::vector
,Esto limpia un poco la sintaxis.
Pero no pude usar la magia de los parámetros de la plantilla de plantilla para hacer que esto funcione en contenedores STL arbitrarios.
Cualquier comentario sobre cómo mejorar la última respuesta sería bueno.
fuente
template<typename CONTAINER, typename CONTAINEE> bool contains(const CONTAINER& container, const CONTAINEE& needle) { return find(container.begin(), container.end(), needle) != container.end();
// Sintaxis general
/ * en el siguiente código, estoy tratando de encontrar el elemento 4 en int set si está presente o no * /
fuente