¿Cómo saber si un elemento está presente en un std :: vector?

616

Todo lo que quiero hacer es verificar si un elemento existe en el vector o no, para poder tratar cada caso.

if ( item_present )
   do_this();
else
   do_that();
Joan Venge
fuente
2
buscar en un vector es muy lento ya que hay que mirar a cada elemento del vector a fin de considerar el uso de un mapa, si está haciendo una gran cantidad de búsquedas
naumcho
77
@naumcho: Si el vector está ordenado, siempre hay una búsqueda binaria, como se publica a continuación. Esto lo hace tan rápido como un mapa y si solo está almacenando valores (no mapas de clave / valor), entonces usará mucha menos memoria.
Adam Hawes
44
los mapas ciertamente no son la mejor opción, pero usar set podría ser útil. Si necesita tiempo de búsqueda O (1), hash_set es el camino a seguir.
Philipp
Una excelente respuesta presente en una pregunta duplicada: stackoverflow.com/a/3451045/472647
CodeMouse92
1
Si va a buscar varias veces diferentes números, una tabla hash sería más eficiente.
NL628

Respuestas:

916

Puedes usar std::finddesde <algorithm>:

#include <vector>
vector<int> vec; 
//can have other data types instead of int but must same datatype as item 
std::find(vec.begin(), vec.end(), item) != vec.end()

Esto devuelve un bool ( truesi está presente, de lo falsecontrario). Con tu ejemplo:

#include <algorithm>
#include <vector>

if ( std::find(vec.begin(), vec.end(), item) != vec.end() )
   do_this();
else
   do_that();
MSN
fuente
216
No veo cómo count () podría ser más rápido que find (), ya que find () se detiene tan pronto como se encuentra un elemento, mientras que count () siempre tiene que escanear toda la secuencia.
Éric Malenfant
114
No te olvides #include <algorithm>o de lo contrario podrías obtener errores muy extraños como 'no se puede encontrar la función de coincidencia en el espacio de nombres
estándar
80
¿No le ha molestado a nadie que, a pesar de que el STL está "orientado a objetos", .find()todavía no es una función miembro std::vector, como cabría esperar? Me pregunto si esto es de alguna manera una consecuencia de la plantilla.
bobobobo
71
@bobobobo: OOP no tiene nada que ver con miembros versus no miembros. Y existe una escuela de pensamiento generalizada de que si algo no tiene que ser miembro, o cuando no ofrece ninguna ventaja cuando se implementa como miembro, entonces no debería ser miembro; std::vector<>::find()no daría ninguna ventaja, ni es necesaria, por lo tanto, no, no debería ser miembro. Ver también en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach
36
@phresnel Yo diría que "cuando no da ninguna ventaja cuando se implementa como miembro" es falso para este caso. La ventaja es una interfaz simplificada y más clara. Por ejemplo: mvec.find(key) != mvec.cend()es preferible a std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog
113

Como otros han dicho, use el STL findo las find_iffunciones. Pero si usted está buscando en grandes vectores y esto afecta al rendimiento, es posible que desee ordenar su vector y luego usar las binary_search, lower_boundo upper_boundalgoritmos.

Brian Neal
fuente
3
¡Buena respuesta! Encontrar siempre es o (n). lower_bound es o (log (n)) si se usa con iteradores de acceso aleatorio.
Stephen Edmonds el
30
Sin embargo, la clasificación es O (nlogn), por lo que vale la pena solo si está haciendo más que búsquedas O (logn).
liori
77
@liori Cierto, depende de tus patrones de uso. Si solo necesita ordenarlo una vez, haga varias búsquedas repetidamente, puede salvarlo.
Brian Neal
1
@Brian Neal, vale la pena ordenar un vector grande si tiene que haber muchas búsquedas de elementos en él. La clasificación será O (nlogn) y O (n) será mejor si uno tiene que encontrar un elemento solo una vez :)
Swapnil B.
47

Use find desde el encabezado del algoritmo de stl. He ilustrado su uso con int type. Puede usar cualquier tipo que desee siempre y cuando pueda comparar la igualdad (sobrecarga == si lo necesita para su clase personalizada).

#include <algorithm>
#include <vector>

using namespace std;
int main()
{   
    typedef vector<int> IntContainer;
    typedef IntContainer::iterator IntIterator;

    IntContainer vw;

    //...

    // find 5
    IntIterator i = find(vw.begin(), vw.end(), 5);

    if (i != vw.end()) {
        // found it
    } else {
        // doesn't exist
    }

    return 0;
}
m-sharp
fuente
2
Dependiendo de las necesidades del OP, find_if () también podría ser apropiado. Permite buscar utilizando un predicado arbitrario en lugar de igualdad.
Éric Malenfant
Vaya, vi tu comentario demasiado tarde. La respuesta que di también menciona find_if.
Frank
39

Si su vector no está ordenado, utilice el enfoque sugerido por MSN:

if(std::find(vector.begin(), vector.end(), item)!=vector.end()){
      // Found the item
}

Si su vector está ordenado, use el método binary_search que Brian Neal sugirió:

if(binary_search(vector.begin(), vector.end(), item)){
     // Found the item
}

la búsqueda binaria produce O (log n) en el peor de los casos, que es mucho más eficiente que el primer enfoque. Para usar la búsqueda binaria, puede usar qsort para ordenar el vector primero y garantizar que esté ordenado.

espiral
fuente
3
No quiere decir std::sort? qsortes muy ineficiente en vectores ... ver: stackoverflow.com/questions/12308243/…
Jason R. Mick
1
La búsqueda binaria funcionará mejor para contenedores más grandes, pero para contenedores pequeños es probable que una búsqueda lineal simple sea tan rápida o más rápida.
BillT
21

Yo uso algo como esto ...

#include <algorithm>


template <typename T> 
const bool Contains( std::vector<T>& Vec, const T& Element ) 
{
    if (std::find(Vec.begin(), Vec.end(), Element) != Vec.end())
        return true;

    return false;
}

if (Contains(vector,item))
   blah
else
   blah

... de esa manera es realmente claro y legible. (Obviamente, puede reutilizar la plantilla en varios lugares).

Andy Krouwel
fuente
y puede hacer que funcione para listas o vectores mediante el uso de 2 nombres de tipo
Erik Aronesty
@ErikAronesty puede salirse con 1 argumento de plantilla si lo usa value_typedesde el contenedor para el tipo de elemento. He agregado una respuesta como esta.
Martin Broadhurst
13

En C ++ 11 puedes usar any_of. Por ejemplo, si es un vector<string> v;entonces:

if (any_of(v.begin(), v.end(), bind(equal_to<string>(), _1, item)))
   do_this();
else
   do_that();

Alternativamente, use una lambda:

if (any_of(v.begin(), v.end(), [&](const std::string& elem) { return elem == item; }))
   do_this();
else
   do_that();
Deqing
fuente
1
bind1sty bind2ndestán en desuso desde C ++ 11 y se eliminan por completo en C ++ 17. Use bindcon placeholdersy / o lambdas en su lugar.
andreee
11

Aquí hay una función que funcionará para cualquier contenedor:

template <class Container> 
const bool contains(const Container& container, const typename Container::value_type& element) 
{
    return std::find(container.begin(), container.end(), element) != container.end();
}

Tenga en cuenta que puede salirse con 1 parámetro de plantilla porque puede extraerlo value_typedel Contenedor. Necesita el typenameporque Container::value_typees un nombre dependiente .

Martin Broadhurst
fuente
55
Tenga en cuenta que esto a veces es demasiado amplio: funcionaría para std :: set, por ejemplo, pero ofrece un rendimiento terrible en comparación con la función de miembro find (). He encontrado que es mejor agregar una especialización para contenedores con una búsqueda más rápida (set / map, no ordenado_ *)
Andy Krouwel
10

Tenga en cuenta que, si va a hacer muchas búsquedas, hay contenedores STL que son mejores para eso. No sé cuál es su aplicación, pero vale la pena considerar los contenedores asociativos como std :: map.

std :: vector es el contenedor de elección a menos que tenga una razón para otra, y las búsquedas por valor pueden ser tal razón.

David Thornley
fuente
Incluso con búsquedas por valor, el vector puede ser una buena opción, siempre que esté ordenado y use binary_search, lower_bound o upper_bound. Si el contenido del contenedor cambia entre búsquedas, el vector no es muy bueno debido a la necesidad de ordenar nuevamente.
Renze de Waal
8

Use la función de búsqueda STL .

Tenga en cuenta que también existe una función find_if , que puede usar si su búsqueda es más compleja, es decir, si no solo está buscando un elemento, sino que, por ejemplo, desea ver si hay un elemento que cumple un cierto condición, por ejemplo, una cadena que comienza con "abc". ( find_ifle daría un iterador que apunta al primer elemento).

Franco
fuente
7

Con boost puedes usar any_of_equal:

#include <boost/algorithm/cxx11/any_of.hpp>

bool item_present = boost::algorithm::any_of_equal(vector, element);
Mikhail
fuente
5

Puedes probar este código:

#include <algorithm>
#include <vector>

// You can use class, struct or primitive data type for Item
struct Item {
    //Some fields
};
typedef std::vector<Item> ItemVector;
typedef ItemVector::iterator ItemIterator;
//...
ItemVector vtItem;
//... (init data for vtItem)
Item itemToFind;
//...

ItemIterator itemItr;
itemItr = std::find(vtItem.begin(), vtItem.end(), itemToFind);
if (itemItr != vtItem.end()) {
    // Item found
    // doThis()
}
else {
    // Item not found
    // doThat()
}
TrungTN
fuente
3

Puede usar la findfunción, que se encuentra en el stdespacio de nombres, es decir std::find. Pasa la std::findfunción the beginy enditerator del vector que desea buscar, junto con el elemento que está buscando y compara el iterador resultante con el final del vector para ver si coinciden o no.

std::find(vector.begin(), vector.end(), item) != vector.end()

También puede desreferenciar ese iterador y usarlo de manera normal, como cualquier otro iterador.

TankorSmash
fuente
3

Puedes usar count también. Devolverá el número de elementos presentes en un vector.

int t=count(vec.begin(),vec.end(),item);
Aditya
fuente
11
findes más rápido que count, porque no sigue contando después del primer partido.
Camille Goudeseune
2

Si quieres encontrar una cadena en un vector:

    struct isEqual
{
    isEqual(const std::string& s): m_s(s)
    {}

    bool operator()(OIDV* l)
    {
        return l->oid == m_s;
    }

    std::string m_s;
};
struct OIDV
{
    string oid;
//else
};
VecOidv::iterator itFind=find_if(vecOidv.begin(),vecOidv.end(),isEqual(szTmp));
Gank
fuente
2

Otra muestra usando operadores C ++.

#include <vector>
#include <algorithm>
#include <stdexcept>

template<typename T>
inline static bool operator ==(const std::vector<T>& v, const T& elem)
{
  return (std::find(v.begin(), v.end(), elem) != v.end());
}

template<typename T>
inline static bool operator !=(const std::vector<T>& v, const T& elem)
{
  return (std::find(v.begin(), v.end(), elem) == v.end());
}

enum CODEC_ID {
  CODEC_ID_AAC,
  CODEC_ID_AC3,
  CODEC_ID_H262,
  CODEC_ID_H263,
  CODEC_ID_H264,
  CODEC_ID_H265,
  CODEC_ID_MAX
};

void main()
{
  CODEC_ID codec = CODEC_ID_H264;
  std::vector<CODEC_ID> codec_list;

  codec_list.reserve(CODEC_ID_MAX);
  codec_list.push_back(CODEC_ID_AAC);
  codec_list.push_back(CODEC_ID_AC3);
  codec_list.push_back(CODEC_ID_H262);
  codec_list.push_back(CODEC_ID_H263);
  codec_list.push_back(CODEC_ID_H264);
  codec_list.push_back(CODEC_ID_H265);

  if (codec_list != codec)
  {
    throw std::runtime_error("codec not found!");
  }

  if (codec_list == codec)
  {
    throw std::logic_error("codec has been found!");
  }
}
Valdemar_Rudolfovich
fuente
44
No recomendaría abusar de la sobrecarga del operador de esa manera.
Leon
2
Leon, estoy de acuerdo contigo, semánticamente no es correcto. Lo uso para hacer pruebas unitarias más claramente.
Valdemar_Rudolfovich
1
template <typename T> bool IsInVector(T what, std::vector<T> * vec)
{
    if(std::find(vec->begin(),vec->end(),what)!=vec->end())
        return true;
    return false;
}
usuario3157855
fuente
1

(C ++ 17 y superior):

puede usar std::searchtambién

Esto también es útil para buscar la secuencia de elementos.

#include <algorithm>
#include <iostream>
#include <vector>

template <typename Container>
bool search_vector(const Container& vec, const Container& searchvec)
{
    return std::search(vec.begin(), vec.end(), searchvec.begin(), searchvec.end()) != vec.end();
}

int main()
{
     std::vector<int> v = {2,4,6,8};

     //THIS WORKS. SEARCHING ONLY ONE ELEMENT.
     std::vector<int> searchVector1 = {2};
     if(search_vector(v,searchVector1))
         std::cout<<"searchVector1 found"<<std::endl;
     else
         std::cout<<"searchVector1 not found"<<std::endl;

     //THIS WORKS, AS THE ELEMENTS ARE SEQUENTIAL.
     std::vector<int> searchVector2 = {6,8};
     if(search_vector(v,searchVector2))
         std::cout<<"searchVector2 found"<<std::endl;
     else
         std::cout<<"searchVector2 not found"<<std::endl;

     //THIS WILL NOT WORK, AS THE ELEMENTS ARE NOT SEQUENTIAL.
     std::vector<int> searchVector3 = {8,6};
     if(search_vector(v,searchVector3))
         std::cout<<"searchVector3 found"<<std::endl;
     else
         std::cout<<"searchVector3 not found"<<std::endl;
}

También hay flexibilidad para pasar algunos algoritmos de búsqueda. Consulte aquí

https://en.cppreference.com/w/cpp/algorithm/search

Pavan Chandaka
fuente
1

Personalmente, he usado plantillas en los últimos tiempos para manejar múltiples tipos de contenedores a la vez en lugar de tratar solo con vectores. Encontré un ejemplo similar en línea (no recuerdo dónde), así que el crédito va a quien sea que haya robado esto. Este patrón particular parece manejar también las matrices en bruto.

template <typename Container, typename T = typename std::decay<decltype(*std::begin(std::declval<Container>()))>::type>
bool contains(Container && c, T v)
{
    return std::find(std::begin(c), std::end(c), v) != std::end(c);
}
Pascal Laferrière
fuente
-4

Usar Newton C ++ es más fácil, auto documentado y más rápido que con std :: find debido a que devuelve un bool directamente.

bool exists_linear( INPUT_ITERATOR first, INPUT_ITERATOR last, const T& value )

bool exists_binary( INPUT_ITERATOR first, INPUT_ITERATOR last, const T& value )

Creo que es obvio lo que hacen las funciones.

include <newton/algorithm/algorithm.hpp>

if ( newton::exists_linear(first, last, value) )
   do_this();
else
   do_that();
Moisés rojo
fuente