Wie finde ich heraus, ob ein Element in einem std :: vector vorhanden ist?


616

Ich möchte nur überprüfen, ob ein Element im Vektor vorhanden ist oder nicht, damit ich mich mit jedem Fall befassen kann.

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

2
in einem Vektor der Suche ist sehr langsam , da Sie bei jedem einzelnen Elemente des Vektors suchen haben , so sollten Sie eine Karte verwenden , wenn Sie eine Menge Lookups tun
naumcho

7
@naumcho: Wenn der Vektor sortiert ist, gibt es immer eine binäre Suche, wie unten angegeben. Dies macht es so schnell wie eine Karte und wenn Sie nur Werte speichern (keine Schlüssel- / Wertekarten), wird es viel weniger Speicher verbrauchen.
Adam Hawes

4
Karten sind sicherlich nicht die beste Wahl, aber die Verwendung von Set kann nützlich sein. Wenn Sie eine Suchzeit von O (1) benötigen, ist hash_set der richtige Weg.
Philipp

Eine hervorragende Antwort auf eine doppelte Frage: stackoverflow.com/a/3451045/472647
CodeMouse92

1
Wenn Sie mehrmals nach verschiedenen Zahlen suchen, ist eine Hash-Tabelle effizienter.
NL628

Antworten:


915

Sie können verwenden std::findvon <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()

Dies gibt einen Bool zurück ( truefalls vorhanden, falseandernfalls). Mit Ihrem Beispiel:

#include <algorithm>
#include <vector>

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

216
Ich sehe nicht, wie count () schneller sein könnte als find (), da find () stoppt, sobald ein Element gefunden wird, während count () immer die gesamte Sequenz scannen muss.
Éric Malenfant

114
Vergessen Sie nicht, #include <algorithm>sonst könnten sehr seltsame Fehler wie "
Ich

80
Hat es niemanden gestört, dass die STL, obwohl sie "objektorientiert" ist, .find()immer noch keine Mitgliedsfunktion von ist std::vector, wie Sie es erwarten würden? Ich frage mich, ob dies irgendwie eine Folge von Vorlagen ist.
Bobobobo

71
@bobobobo: OOP hat nichts mit Mitgliedern oder Nichtmitgliedern zu tun. Und es gibt eine weit verbreitete Denkrichtung: Wenn etwas kein Mitglied sein muss oder wenn es bei der Implementierung als Mitglied keinen Vorteil bringt, sollte es kein Mitglied sein. std::vector<>::find()würde keinen Vorteil geben, noch ist es erforderlich, daher nein, es sollte kein Mitglied sein. Siehe auch en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach

36
@phresnel Ich würde argumentieren, dass "wenn es keinen Vorteil bringt, wenn es als Mitglied implementiert wird" für diesen Fall falsch ist. Der Vorteil ist eine vereinfachte und übersichtlichere Oberfläche. Zum Beispiel: mvec.find(key) != mvec.cend()ist vorzuziehen std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
Swalog

113

Verwenden Sie, wie bereits erwähnt, die STL findoder find_ifFunktionen. Aber wenn man in sehr großen Vektoren und diese Auswirkungen Leistung sucht, mögen Sie vielleicht Ihren Vektor sortieren und dann mit dem binary_search, lower_boundoder upper_boundAlgorithmen.


3
Gute Antwort! Finden ist immer o (n). lower_bound ist o (log (n)), wenn es mit Iteratoren mit wahlfreiem Zugriff verwendet wird.
Stephen Edmonds

30
Das Sortieren ist jedoch O (nlogn), daher lohnt es sich nur, wenn Sie mehr als O (logn) suchen.
Liori

7
@liori Richtig, es hängt von Ihren Nutzungsmustern ab. Wenn Sie es nur einmal sortieren müssen, führen Sie wiederholt viele Suchvorgänge durch, um Sie zu retten.
Brian Neal

1
@ Brian Neal, das Sortieren eines großen Vektors lohnt sich, wenn viele Elementsuchen durchgeführt werden müssen. Die Sortierung ist O (nlogn) und O (n) ist besser, wenn man ein Element nur einmal finden muss :)
Swapnil B.

47

Verwenden Sie find aus dem Algorithmus-Header von stl. Ich habe die Verwendung mit dem Typ int veranschaulicht. Sie können einen beliebigen Typ verwenden, solange Sie ihn auf Gleichheit vergleichen können (Überladung ==, falls erforderlich, für Ihre benutzerdefinierte Klasse).

#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
Abhängig von den Anforderungen des OP kann auch find_if () geeignet sein. Es ermöglicht die Suche mit einem beliebigen Prädikat anstelle von Gleichheit.
Éric Malenfant

Hoppla, habe deinen Kommentar zu spät gesehen. Die Antwort, die ich gab, erwähnt auch find_if.
Frank

39

Wenn Ihr Vektor nicht geordnet ist, verwenden Sie den von MSN vorgeschlagenen Ansatz:

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

Wenn Ihr Vektor geordnet ist, verwenden Sie die von Brian Neal vorgeschlagene Methode binary_search:

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

Die binäre Suche ergibt eine O (log n) Worst-Case-Leistung, die weitaus effizienter ist als der erste Ansatz. Um die binäre Suche zu verwenden, können Sie den Vektor zuerst mit qsort sortieren, um sicherzustellen, dass er geordnet ist.


3
Meinst du nicht std::sort? qsortist sehr ineffizient auf Vektoren .... siehe: stackoverflow.com/questions/12308243/…
Jason R. Mick

1
Die binäre Suche ist bei größeren Containern besser, bei kleinen Containern ist eine einfache lineare Suche jedoch wahrscheinlich genauso schnell oder schneller.
BillT

21

Ich benutze so etwas ...

#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

... so ist es eigentlich klar und lesbar. (Natürlich können Sie die Vorlage an mehreren Stellen wiederverwenden.)


und Sie können es für Listen oder Vektoren arbeiten lassen, indem Sie 2 Typnamen verwenden
Erik Aronesty

@ErikAronesty Sie können mit 1 Vorlagenargument davonkommen, wenn Sie value_typeaus dem Container für den Elementtyp verwenden. Ich habe eine Antwort wie diese hinzugefügt.
Martin Broadhurst

13

In C ++ 11 können Sie verwenden any_of. Zum Beispiel, wenn es ein vector<string> v;Dann ist:

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

Alternativ können Sie ein Lambda verwenden:

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

1
bind1stund bind2ndsind seit C ++ 11 veraltet und in C ++ 17 vollständig entfernt. Verwenden Sie stattdessen bindmit placeholdersund / oder Lambdas.
Andreee

11

Hier ist eine Funktion, die für jeden Container funktioniert:

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

Beachten Sie, dass Sie mit 1 Vorlagenparameter davonkommen können, da Sie die value_typeaus dem Container extrahieren können . Sie benötigen das typenameweil Container::value_typeist ein abhängiger Name .


5
Beachten Sie, dass dies manchmal etwas zu weit gefasst ist - es funktioniert beispielsweise für std :: set, bietet aber im Vergleich zur Funktion find () member eine schreckliche Leistung. Ich habe es am besten gefunden, eine Spezialisierung für Container mit einer schnelleren Suche hinzuzufügen (set / map, unordered_ *)
Andy Krouwel

10

Denken Sie daran, dass es STL-Container gibt, die dafür besser geeignet sind, wenn Sie viele Suchvorgänge durchführen. Ich weiß nicht, was Ihre Anwendung ist, aber assoziative Container wie std :: map sind möglicherweise eine Überlegung wert.

std :: vector ist der Container der Wahl, es sei denn, Sie haben einen Grund für einen anderen, und die Suche nach Wert kann ein solcher Grund sein.


Selbst bei der Suche nach Wert kann der Vektor eine gute Wahl sein, solange er sortiert ist und Sie binäre Suche, untere Grenze oder obere Grenze verwenden. Wenn sich der Inhalt des Containers zwischen den Suchvorgängen ändert, ist der Vektor nicht sehr gut, da erneut sortiert werden muss.
Renze de Waal

8

Verwenden Sie die STL- Suchfunktion .

Beachten Sie, dass es auch eine find_if- Funktion gibt, die Sie verwenden können, wenn Ihre Suche komplexer ist, dh wenn Sie nicht nur nach einem Element suchen, sondern beispielsweise sehen möchten, ob es ein Element gibt, das eine bestimmte Funktion erfüllt Bedingung ist beispielsweise eine Zeichenfolge, die mit "abc" beginnt. ( find_ifwürde Ihnen einen Iterator geben, der auf das erste derartige Element zeigt).


7

Mit Boost können Sie verwenden any_of_equal:

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

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

5

Sie können diesen Code ausprobieren:

#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

Sie können die findFunktion verwenden, die sich im stdNamespace befindet, dh std::find. Sie übergeben die std::findFunktion beginund den endIterator des zu suchenden Vektors zusammen mit dem gesuchten Element und vergleichen den resultierenden Iterator mit dem Ende des Vektors, um festzustellen, ob sie übereinstimmen oder nicht.

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

Sie können diesen Iterator auch dereferenzieren und wie jeden anderen Iterator wie gewohnt verwenden.


3

Sie können auch count verwenden. Es wird die Anzahl der in einem Vektor vorhandenen Elemente zurückgegeben.

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

11
findist schneller als count, weil es nach dem ersten Spiel nicht mehr zählt.
Camille Goudeseune

2

Wenn Sie eine Zeichenfolge in einem Vektor finden möchten:

    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

Ein weiteres Beispiel mit C ++ - Operatoren.

#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
Ich würde nicht empfehlen, die Überlastung des Bedieners so zu missbrauchen.
Leon

2
Leon, ich stimme dir zu, semantisch ist es nicht richtig. Ich benutze es, um Unit-Tests klarer zu machen.
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 und höher):

kann std::searchauch verwenden

Dies ist auch nützlich für die Suche nach einer Folge von Elementen.

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

Es besteht auch die Flexibilität, einige Suchalgorithmen zu übergeben. Siehe hier.

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


1

Ich habe in letzter Zeit persönlich Vorlagen verwendet, um mehrere Arten von Containern gleichzeitig zu verarbeiten, anstatt nur Vektoren zu behandeln. Ich habe ein ähnliches Beispiel online gefunden (kann mich nicht erinnern, wo), also geht der Kredit an denjenigen, von dem ich das gestohlen habe. Dieses spezielle Muster scheint auch mit rohen Arrays umzugehen.

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

Mit Newton C ++ ist es einfacher, selbstdokumentierter und schneller als mit std :: find, da ein Bool direkt zurückgegeben wird.

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

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

Ich denke, es ist offensichtlich, was die Funktionen tun.

include <newton/algorithm/algorithm.hpp>

if ( newton::exists_linear(first, last, value) )
   do_this();
else
   do_that();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.