Come scoprire se un elemento è presente in uno std :: vector?


616

Tutto quello che voglio fare è verificare se esiste un elemento nel vettore o meno, in modo da poter affrontare ogni caso.

if ( item_present )
   do_this();
else
   do_that();

2
la ricerca in un vettore è molto lenta poiché devi guardare ogni singolo elemento del vettore, quindi considera di usare una mappa se stai facendo molte ricerche
naumcho,

7
@naumcho: se il vettore è ordinato c'è sempre una ricerca binaria, come pubblicato di seguito. Questo lo rende veloce come una mappa e se stai memorizzando solo valori (non mappe chiave / valore), userà molta meno memoria.
Adam Hawes,

4
le mappe non sono certamente la scelta migliore, ma usare set potrebbe essere utile. Se hai bisogno di tempo di ricerca O (1), hash_set è la strada da percorrere.
Philipp

Una risposta superba presenti su una questione duplicato: stackoverflow.com/a/3451045/472647
CodeMouse92

1
Se stai cercando più volte numeri diversi, una tabella hash sarebbe più efficiente.
NL628,

Risposte:


915

Puoi usare std::findda <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()

Questo restituisce un bool ( truese presente, falsealtrimenti). Con il tuo esempio:

#include <algorithm>
#include <vector>

if ( std::find(vec.begin(), vec.end(), item) != vec.end() )
   do_this();
else
   do_that();

216
Non vedo come count () potrebbe essere più veloce di find (), poiché find () si interrompe non appena viene trovato un elemento, mentre count () deve sempre scansionare l'intera sequenza.
Éric Malenfant,

114
Non dimenticare #include <algorithm>o potresti ricevere errori molto strani come 'impossibile trovare la funzione di corrispondenza nello spazio dei nomi std'
rustyx

80
Non è preso la briga qualcuno che, nonostante lo STL essere "object-oriented", .find()è ancora non è una funzione di membro di std::vector, come ci si aspetterebbe che dovrebbe essere? Mi chiedo se questa sia in qualche modo una conseguenza del templating.
Bobobobo,

71
@bobobobo: OOP non ha nulla a che fare con membri e non membri. E c'è una diffusa scuola di pensiero che se qualcosa non deve essere un membro, o quando non dà alcun vantaggio quando implementato come membro, di quanto non dovrebbe essere un membro; std::vector<>::find()non darebbe alcun vantaggio, né è necessario, quindi no, non dovrebbe essere un membro. Vedi anche en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach

36
@phresnel Direi che "quando non dà alcun vantaggio se implementato come membro" è falso per questo caso. Il vantaggio è un'interfaccia semplificata e più chiara. Ad esempio: mvec.find(key) != mvec.cend()è preferibile std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog

113

Come altri hanno già detto, utilizzare l'STL findo le find_iffunzioni. Ma se siete alla ricerca in grandi vettori e questo influisce sulle prestazioni, si consiglia di ordinare la vostra vettoriale e quindi utilizzare i binary_search, lower_boundo upper_boundalgoritmi.


3
Buona risposta! Trova è sempre o (n). lower_bound è o (log (n)) se utilizzato con iteratori ad accesso casuale.
Stephen Edmonds,

30
L'ordinamento è O (nlogn), quindi vale la pena solo se stai facendo più di O (logn) ricerche.
liori,

7
@liori True dipende dai modelli di utilizzo. Se hai bisogno di ordinarlo solo una volta, quindi fai ripetutamente molte ricerche per salvarti.
Brian Neal,

1
@Brian Neal, vale la pena ordinare un vettore grande se ci devono essere molte ricerche di elementi su di esso. L'ordinamento sarà O (nlogn) e O (n) sarà migliore se si deve trovare un elemento solo una volta :)
Swapnil B.

47

Usa find dall'intestazione dell'algoritmo di stl. Ho illustrato il suo uso con il tipo int. Puoi usare qualsiasi tipo ti piaccia purché sia ​​possibile confrontare per uguaglianza (sovraccarico == se necessario per la propria classe personalizzata).

#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
A seconda delle esigenze del PO, find_if () potrebbe anche essere appropriato. Permette di cercare usando un predicato arbitrario invece di uguaglianza.
Éric Malenfant,

Oops, ho visto il tuo commento troppo tardi. La risposta che ho dato menziona anche find_if.
Frank,

39

Se il tuo vettore non è ordinato, utilizza l'approccio suggerito da MSN:

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

Se il tuo vettore è ordinato, usa il metodo binary_search suggerito da Brian Neal:

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

la ricerca binaria produce le prestazioni del caso peggiore O (log n), che è molto più efficiente del primo approccio. Per utilizzare la ricerca binaria, è possibile utilizzare qsort per ordinare prima il vettore per garantire che sia ordinato.


3
Non intendi std::sort? qsortè molto inefficiente sui vettori .... vedi: stackoverflow.com/questions/12308243/…
Jason R. Mick

1
La ricerca binaria funzionerà meglio per i contenitori più grandi, ma per i piccoli contenitori è probabile che una semplice ricerca lineare sia altrettanto veloce o più veloce.
BillT

21

Uso qualcosa del genere ...

#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

... in questo modo è in realtà chiaro e leggibile. (Ovviamente puoi riutilizzare il modello in più punti).


e puoi farlo funzionare per elenchi o vettori usando 2
nomi di caratteri

@ErikAronesty puoi cavartela con 1 argomento template se usi value_typedal contenitore per il tipo di elemento. Ho aggiunto una risposta come questa.
Martin Broadhurst,

13

In C ++ 11 è possibile utilizzare any_of. Ad esempio se è un vector<string> v;allora:

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

In alternativa, usa un lambda:

if (any_of(v.begin(), v.end(), [&](const std::string& elem) { return elem == item; }))
   do_this();
else
   do_that();

1
bind1ste bind2ndsono deprecati dal C ++ 11 e completamente rimossi in C ++ 17. Utilizzare invece bindcon placeholderse / o lambdas.
andreee

11

Ecco una funzione che funzionerà per qualsiasi contenitore:

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

Si noti che è possibile cavarsela con 1 parametro del modello perché è possibile estrarre value_typedal contenitore. È necessario il typenameperché Container::value_typeè un nome dipendente .


5
Si noti che a volte questo è un po 'troppo ampio - funzionerebbe per std :: set per esempio, ma darebbe prestazioni terribili rispetto alla funzione membro find (). Ho trovato la soluzione migliore per aggiungere una specializzazione per i contenitori con una ricerca più veloce (set / map, unordered_ *)
Andy Krouwel

10

Tieni presente che, se hai intenzione di fare molte ricerche, ci sono contenitori STL che sono meglio per questo. Non so quale sia la tua applicazione, ma vale la pena prendere in considerazione contenitori associativi come std :: map.

std :: vector è il contenitore preferito a meno che tu non abbia una ragione per un'altra, e le ricerche in base al valore possono essere una tale ragione.


Anche con ricerche in base al valore, il vettore può essere una buona scelta, purché sia ​​ordinato e utilizzi binary_search, lower_bound o upper_bound. Se il contenuto del contenitore cambia tra le ricerche, il vettore non è molto buono a causa della necessità di riordinare.
Renze de Waal,

8

Utilizzare la funzione di ricerca STL .

Tieni presente che esiste anche una funzione find_if , che puoi utilizzare se la tua ricerca è più complessa, ad esempio se non stai solo cercando un elemento, ma, ad esempio, vuoi vedere se esiste un elemento che soddisfa un certo condizione, ad esempio, una stringa che inizia con "abc". ( find_ifti darebbe un iteratore che punta al primo di questi elementi).


7

Con boost puoi usare any_of_equal:

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

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

5

Puoi provare questo codice:

#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

È possibile utilizzare la findfunzione, presente nello stdspazio dei nomi, ad es std::find. Si passa la std::findfunzione the begine enditeratore dal vettore che si desidera cercare, insieme all'elemento che si sta cercando e si confronta l'iteratore risultante con la fine del vettore per vedere se corrispondono o meno.

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

Puoi anche dereferenziare quell'iteratore e usarlo normalmente, come qualsiasi altro iteratore.


3

Puoi usare anche count. Restituirà il numero di elementi presenti in un vettore.

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

11
findè più veloce di count, perché non continua a contare dopo la prima partita.
Camille Goudeseune,

2

Se vuoi trovare una stringa in un vettore:

    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

Un altro esempio che utilizza operatori 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!");
  }
}

4
Non consiglierei di abusare del sovraccarico dell'operatore in questo modo.
Leon,

2
Leon, sono d'accordo con te, semanticamente non è corretto. Lo uso per rendere più chiari i test unitari.
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 e versioni successive):

può usare std::searchanche

Questo è utile anche per la ricerca di sequenze di elementi.

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

Inoltre c'è la flessibilità di passare alcuni algoritmi di ricerca. Fare riferimento qui

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


1

Ho usato personalmente modelli di recente per gestire più tipi di contenitori contemporaneamente anziché occuparmi solo dei vettori. Ho trovato un esempio simile online (non ricordo dove), quindi il merito va a chiunque abbia rubato questo. Questo particolare modello sembra gestire anche array grezzi.

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

L'utilizzo di Newton C ++ è più semplice, autocertificato e più rapido rispetto a std :: find a causa della restituzione di un bool direttamente.

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

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

Penso che sia ovvio cosa facciano le funzioni.

include <newton/algorithm/algorithm.hpp>

if ( newton::exists_linear(first, last, value) )
   do_this();
else
   do_that();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.