Bir öğenin std :: vector'da olup olmadığını nasıl öğrenebilirim?


616

Tüm yapmak istediğim, bir elemanın vektörde var olup olmadığını kontrol etmektir, böylece her durumla başa çıkabilirim.

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

2
bir vektörde arama yapmak çok yavaştır, çünkü vektörün her bir elementine bakmak zorundasınız, bu yüzden çok fazla arama yapıyorsanız bir harita kullanmayı düşünün
naumcho

7
@ naumcho: Vektör sıralanırsa, aşağıda gösterildiği gibi her zaman ikili arama vardır. Bu, onu harita kadar hızlı hale getirir ve yalnızca değerleri (anahtar / değer haritaları değil) saklıyorsanız, çok daha az bellek kullanır.
Adam Hawes

4
haritalar kesinlikle en iyi seçim değildir, ancak set kullanmak yararlı olabilir. O (1) arama süresine ihtiyacınız varsa, hash_set gitmenin yoludur.
Philipp

Yinelenen bir soruda mükemmel bir cevap var: stackoverflow.com/a/3451045/472647
CodeMouse92

1
Farklı numaralar için birden çok kez arama yapacaksanız, bir karma tablosu daha verimli olur.
NL628

Yanıtlar:


915

Sen kullanabilirsiniz std::findden <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()

Bu bir bool döndürür ( truevarsa, falseaksi takdirde). Örneğinizle:

#include <algorithm>
#include <vector>

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

216
Count () her zaman tüm diziyi taramak zorunda kalırken find () durduğundan, count () işlevinin find () 'den daha hızlı olabileceğini görmüyorum.
Éric Malenfant

114
Unutmayın #include <algorithm>ya da 'ad alanı
std'de

80
STL'nin "nesne yönelimli" olmasına rağmen, beklediğiniz gibi .find()hala bir üye işlevi olmadığı kimseyi rahatsız std::vectoretmedi mi? Bunun bir şekilde baştan çıkarmanın bir sonucu olup olmadığını merak ediyorum.
bobobobo

71
@bobobobo: OOP'nin üyeler ve üye olmayanlarla ilgisi yoktur. Ve bir şeyin üye olması gerekmiyorsa veya üye olarak uygulandığında herhangi bir avantaj sağlamazsa, üye olmaması gerektiğine dair yaygın bir düşünce okulu vardır; std::vector<>::find()herhangi bir avantaj sağlamaz, ne de gerekli değildir, bu nedenle hayır, üye olmamalıdır. Ayrıca bkz. En.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach

36
@phresnel "üye olarak uygulandığında herhangi bir avantaj sağlamadığında" bu dava için yanlış olduğunu iddia ediyorum. Avantaj basitleştirilmiş ve daha net bir arayüzdür. Örneğin: mvec.find(key) != mvec.cend()tercih edilir std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog

113

Diğerlerinin söylediği gibi, STL'yi kullanın find veya find_ifişlevleri . Çok büyük vektörler arama ve bu etkiler performansı vardır Ama eğer vektör sıralamak istiyorum, sonra kullanabilir binary_search, lower_boundveya upper_boundalgoritmalar.


3
İyi cevap! Bul her zaman o (n) 'dir. Rastgele erişimli yineleyicilerle kullanılırsa, alt_bound o (log (n)) olur.
Stephen Edmonds

30
Sıralama O (nlogn) olsa da, yalnızca O (logn) 'den fazla arama yapıyorsanız buna değer.
liori

7
@liori Doğru kullanım şekline bağlıdır. Sadece bir kez sıralamanız gerekiyorsa, tekrar tekrar birçok arama yapabilirsiniz.
Brian Neal

1
@Brian Neal, üzerinde çok sayıda eleman araması olması gerekiyorsa, büyük bir vektörü sıralamaya değer. Sıralama bir :) sadece bir kez bir öğe bulmak için varsa O (nlogn) ve O (n) daha iyi olacak olacak
Swapnil B

47

St türünün algoritma başlığından find komutunu kullanın. İnt türüyle kullanımını gösterdim. Eşitliği karşılaştırabildiğiniz sürece istediğiniz herhangi bir türü kullanabilirsiniz (özel sınıfınız için ihtiyacınız varsa aşırı yük ==).

#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
OP'nin ihtiyaçlarına bağlı olarak find_if () de uygun olabilir. Eşitlik yerine keyfi bir yüklem kullanarak arama yapılmasına izin verir.
Éric Malenfant

Hata! Yorumunuzu çok geç gördünüz. Verdiğim cevap find_if'ten de bahsediyor.
Frank

39

Vektörünüz sipariş edilmemişse, MSN'in önerdiği yaklaşımı kullanın:

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

Vektörünüz sipariş edildiyse, Brian Neal'ın önerdiği binary_search yöntemini kullanın:

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

ikili arama ilk yaklaşımdan çok daha verimli olan O (log n) en kötü durum performansını verir. İkili aramayı kullanmak için, vektörü sipariş edildiğini garanti etmek üzere önce sıralamak için qsort'u kullanabilirsiniz.


3
Bunu mu demek istediniz std::sort? qsortvektörler üzerinde çok verimsiz .... bakınız: stackoverflow.com/questions/12308243/…
Jason R. Mick

1
İkili arama, daha büyük kaplar için daha iyi performans gösterir, ancak küçük kaplar için basit bir doğrusal aramanın daha hızlı veya daha hızlı olması muhtemeldir.
BillT

21

Böyle bir şey kullanıyorum ...

#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

... bu şekilde aslında net ve okunabilir. (Açıkçası şablonu birden fazla yerde kullanabilirsiniz).



@ErikAronesty value_type, öğe türü için kapsayıcıdan kullanırsanız 1 şablon bağımsız değişkeni ile kurtulabilirsiniz . Bunun gibi bir cevap ekledim.
Martin Broadhurst

13

C ++ 11'de kullanabilirsiniz any_of. Örneğin, bir vector<string> v;o zaman:

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

Alternatif olarak, bir lambda kullanın:

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

1
bind1stve bind2ndedilmiştir , 11 C ++ yana kaldırıldı ve tamamen 17 C ++ uzaklaştırıldı. Kullanım bindile placeholdersyerine ve / veya lambdas.
andreee

11

İşte herhangi bir Kapsayıcı için çalışacak bir işlev:

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

Kaptan ayıklayabileceğiniz için 1 şablon parametresiyle uzaklaşabileceğinizi unutmayın value_type. İhtiyacınız typenameçünkü Container::value_typebir olan bağımlı isim .


5
Bunun bazen biraz fazla geniş olduğunu unutmayın - örneğin std :: set için işe yarayacaktır, ancak find () üye işlevine kıyasla korkunç bir performans sergileyecektir. Daha hızlı arama yapan konteynerler için bir uzmanlık eklemek en iyisini buldum (set / map, unordered_ *)
Andy Krouwel

10

Çok fazla arama yapacaksanız, bunun için daha iyi olan STL kapları olduğunu unutmayın. Uygulamanızın ne olduğunu bilmiyorum, ancak std :: map gibi ilişkisel kaplar dikkate değer olabilir.

std :: vector, başka bir nedeniniz olmadığı sürece tercih edilen kaptır ve değere göre aramalar böyle bir neden olabilir.


Değere göre aramalarda bile, sıralandığı ve binary_search, lower_bound veya upper_bound kullandığınız sürece vektör iyi bir seçim olabilir. Kabın içeriği aramalar arasında değişirse, tekrar sıralama ihtiyacı nedeniyle vektör çok iyi değildir.
Renze de Waal

8

STL bulmayı kullanın işlevini .

Aramanız daha karmaşıksa, yani yalnızca bir öğe aramıyorsanız, örneğin, belirli bir öğeyi karşılayan bir öğe olup olmadığını görmek istediğiniz bir find_if işlevi olduğunu unutmayın. koşul, örneğin, "abc" ile başlayan bir dize. ( find_ifbu tür ilk öğeye işaret eden bir yineleyici verir).


7

Boost ile şunları kullanabilirsiniz any_of_equal:

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

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

5

Bu kodu deneyebilirsiniz:

#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

Ad alanında findbulunan işlevi kullanabilirsiniz std, yani std::find. Geçtin std::findfonksiyonu beginve endonlar maç ya da değil eğer elemanı ile birlikte aradığınız, arama ve karşılaştırmak istediğiniz vektör gelen yineleyici vektör sonuna kadar yineleyici çıkan görmek için.

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

Ayrıca yineleyiciyi kaldırabilir ve diğer yineleyiciler gibi normal olarak kullanabilirsiniz.


3

Sayıyı da kullanabilirsiniz. Bir vektörde bulunan öğe sayısını döndürür.

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

11
finddaha hızlıdır count, çünkü ilk maçtan sonra saymaya devam etmez.
Camille Goudeseune

2

Bir vektörde dize bulmak istiyorsanız:

    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

C ++ işleçlerini kullanan başka bir örnek.

#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
Operatörün aşırı yüklenmesini bu şekilde kötüye kullanmasını önermem.
Leon

2
Leon, sana katılıyorum, anlamsal olarak doğru değil. Birim testlerini daha net yapmak için kullanıyorum.
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 ve üstü):

kullanabilirsiniz std::search da

Bu aynı zamanda elemanların sırasını aramak için de yararlıdır.

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

Ayrıca bazı arama algoritmalarını geçirme esnekliği vardır. Buraya bakın.

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


1

Kişisel olarak geç kalıpları sadece vektörlerle uğraşmak yerine aynı anda birden fazla kap türünü işlemek için kullandım. Benzer bir örnek çevrimiçi buldum (nerede hatırlayamıyorum) bu yüzden kredi bunu çaldı kim olursa olsun gider. Bu özel örüntü ham dizileri de ele almaktadır.

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

Newton C ++ kullanarak , doğrudan bir bool döndürmesi nedeniyle std :: find'a göre daha kolay, kendi kendine belgelenmiş ve daha hızlıdır.

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

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

Bence fonksiyonların ne yaptığı açık.

include <newton/algorithm/algorithm.hpp>

if ( newton::exists_linear(first, last, value) )
   do_this();
else
   do_that();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.