¿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();

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();

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.


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;
}

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.


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).


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();

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 .


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.


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).


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);

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()
}

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.


3

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

int t=count(vec.begin(),vec.end(),item);

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));

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!");
  }
}

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;
}

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


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);
}

-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();
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.