Bagaimana cara mengetahui apakah suatu item ada dalam std :: vector?

616

Yang ingin saya lakukan adalah memeriksa apakah ada elemen dalam vektor atau tidak, jadi saya bisa menangani setiap kasus.

if ( item_present )
   do_this();
else
   do_that();
Joan Venge
sumber
2
mencari dalam vektor sangat lambat karena Anda harus melihat setiap elemen dari vektor jadi pertimbangkan untuk menggunakan peta jika Anda melakukan banyak pencarian
naumcho
7
@naumcho: Jika vektor diurutkan selalu ada pencarian biner, seperti yang diposting di bawah ini. Ini membuatnya secepat peta dan jika Anda hanya menyimpan nilai (bukan peta kunci / nilai) maka itu akan menggunakan memori yang jauh lebih sedikit.
Adam Hawes
4
peta tentu bukan pilihan terbaik, tetapi menggunakan set mungkin berguna. Jika Anda membutuhkan O (1) waktu pencarian, hash_set adalah cara untuk pergi.
Philipp
Jawaban yang luar biasa hadir pada pertanyaan duplikat: stackoverflow.com/a/3451045/472647
CodeMouse92
1
Jika Anda akan mencari beberapa kali untuk nomor yang berbeda, tabel hash akan lebih efisien.
NL628

Jawaban:

915

Anda dapat menggunakan std::finddari <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()

Ini mengembalikan bool ( truejika ada, falsejika tidak). Dengan contoh Anda:

#include <algorithm>
#include <vector>

if ( std::find(vec.begin(), vec.end(), item) != vec.end() )
   do_this();
else
   do_that();
MSN
sumber
216
Saya tidak melihat bagaimana count () bisa lebih cepat daripada find (), karena find () berhenti segera setelah satu elemen ditemukan, sementara count () selalu harus memindai seluruh urutan.
Éric Malenfant
114
Jangan lupa #include <algorithm>atau Anda mungkin mendapatkan kesalahan yang sangat aneh seperti 'tidak dapat menemukan fungsi yang cocok di namespace std'
rustyx
80
Apakah itu tidak mengganggu siapa pun yang meskipun STL "berorientasi objek", .find()masih bukan fungsi anggota std::vector, seperti yang Anda harapkan seharusnya? Saya ingin tahu apakah ini merupakan konsekuensi dari templating.
bobobobo
71
@bobobobo: OOP tidak ada hubungannya dengan anggota vs. bukan anggota. Dan ada mazhab pemikiran luas bahwa jika sesuatu tidak harus menjadi anggota, atau ketika itu tidak memberikan keuntungan apa pun ketika diterapkan sebagai anggota, maka itu tidak boleh menjadi anggota; std::vector<>::find()tidak akan memberikan keuntungan, juga tidak diperlukan, oleh karena itu, tidak, tidak boleh menjadi anggota Lihat juga en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach
36
@ respir Saya berpendapat bahwa "ketika tidak memberikan keuntungan apa pun ketika diterapkan sebagai anggota" adalah salah untuk kasus ini. Keuntungannya adalah antarmuka yang disederhanakan dan lebih jelas. Misalnya: mvec.find(key) != mvec.cend()lebih disukai daripada std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog
113

Seperti yang orang lain katakan, gunakan STL findatau find_iffungsinya. Tetapi jika Anda sedang mencari dalam vektor yang sangat besar dan kinerja dampak ini, Anda mungkin ingin mengurutkan vektor Anda dan kemudian menggunakan binary_search, lower_boundatau upper_boundalgoritma.

Brian Neal
sumber
3
Jawaban yang bagus! Temukan selalu o (n). lower_bound adalah o (log (n)) jika digunakan dengan iterator akses acak.
Stephen Edmonds
30
Penyortiran adalah O (nlogn), jadi itu hanya bernilai jika Anda melakukan lebih dari pencarian O (logn).
liori
7
@liori Benar itu tergantung pada pola penggunaan Anda. Jika Anda hanya perlu mengurutkannya sekali, maka berulang kali lakukan banyak pencarian yang bisa menyelamatkan Anda.
Brian Neal
1
@Brian Neal, mengurutkan vektor besar bernilai jika harus ada banyak pencarian elemen di atasnya. Penyortiran akan menjadi O (nlogn) dan O (n) akan lebih baik jika seseorang harus menemukan elemen hanya sekali :)
Swapnil B.
47

Gunakan find dari header algoritma stl. Saya telah menggambarkan penggunaannya dengan tipe int. Anda dapat menggunakan jenis apa pun yang Anda suka selama Anda dapat membandingkan untuk kesetaraan (kelebihan == jika Anda perlu untuk kelas kustom Anda).

#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-tajam
sumber
2
Bergantung pada kebutuhan OP, find_if () juga bisa sesuai. Hal ini memungkinkan untuk mencari menggunakan predikat sewenang-wenang alih-alih kesetaraan.
Éric Malenfant
Ups, lihat komentar Anda terlambat. Jawaban yang saya berikan juga menyebutkan find_if.
Frank
39

Jika vektor Anda tidak dipesan, gunakan pendekatan yang disarankan MSN:

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

Jika vektor Anda dipesan, gunakan metode binary_search Brian Neal yang disarankan:

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

pencarian biner menghasilkan O (log n) kinerja kasus terburuk, yang jauh lebih efisien daripada pendekatan pertama. Untuk menggunakan pencarian biner, Anda dapat menggunakan qsort untuk mengurutkan vektor terlebih dahulu untuk memastikan itu dipesan.

spiralmoon
sumber
3
Bukankah maksud Anda std::sort? qsortsangat tidak efisien pada vektor .... lihat: stackoverflow.com/questions/12308243/…
Jason R. Mick
1
Pencarian biner akan berkinerja lebih baik untuk wadah yang lebih besar, tetapi untuk wadah kecil, pencarian linier sederhana cenderung lebih cepat, atau lebih cepat.
BillT
21

Saya menggunakan sesuatu seperti ini ...

#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

... seperti itu sebenarnya jelas dan dapat dibaca. (Jelas Anda dapat menggunakan kembali templat di banyak tempat).

Andy Krouwel
sumber
dan Anda dapat membuatnya berfungsi untuk daftar atau vektor dengan menggunakan 2 nama ketik
Erik Aronesty
@ErikAronesty Anda bisa lolos dengan 1 argumen templat jika Anda gunakan value_typedari wadah untuk jenis elemen. Saya telah menambahkan jawaban seperti ini.
Martin Broadhurst
13

Di C ++ 11 Anda dapat menggunakan any_of. Sebagai contoh jika itu adalah vector<string> v;maka:

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

Atau, gunakan lambda:

if (any_of(v.begin(), v.end(), [&](const std::string& elem) { return elem == item; }))
   do_this();
else
   do_that();
Deqing
sumber
1
bind1stdan bind2ndsudah usang sejak C ++ 11 dan sepenuhnya dihapus di C ++ 17. Gunakan binddengan placeholdersdan / atau lambda sebagai gantinya.
andreee
11

Inilah fungsi yang akan bekerja untuk semua Kontainer:

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

Perhatikan bahwa Anda dapat lolos dengan 1 parameter templat karena Anda dapat mengekstraknya value_typedari Container. Anda memerlukan typenamekarena itu Container::value_typeadalah nama dependen .

Martin Broadhurst
sumber
5
Perhatikan bahwa ini kadang-kadang agak terlalu luas - ini akan berfungsi untuk std :: set misalnya, tetapi memberikan kinerja yang buruk dibandingkan dengan fungsi anggota find (). Saya telah menemukan yang terbaik untuk menambahkan spesialisasi untuk wadah dengan pencarian yang lebih cepat (set / peta, unordered_ *)
Andy Krouwel
10

Ingatlah bahwa, jika Anda akan melakukan banyak pencarian, ada wadah STL yang lebih baik untuk itu. Saya tidak tahu apa aplikasi Anda, tetapi wadah asosiatif seperti std :: map mungkin perlu dipertimbangkan.

std :: vector adalah wadah pilihan kecuali Anda memiliki alasan untuk yang lain, dan pencarian berdasarkan nilai dapat menjadi alasan seperti itu.

David Thornley
sumber
Bahkan dengan pencarian berdasarkan nilai vektor bisa menjadi pilihan yang baik, asalkan diurutkan dan Anda menggunakan binary_search, lower_bound atau upper_bound. Jika isi wadah berubah di antara pencarian, vektor tidak terlalu bagus karena kebutuhan untuk menyortir lagi.
Renze de Waal
8

Gunakan fungsi temukan STL .

Ingatlah bahwa ada juga fungsi find_if , yang dapat Anda gunakan jika pencarian Anda lebih kompleks, yaitu jika Anda tidak hanya mencari elemen, tetapi, misalnya, ingin melihat apakah ada elemen yang memenuhi elemen tertentu kondisi, misalnya, string yang dimulai dengan "abc". ( find_ifakan memberi Anda iterator yang menunjuk ke elemen tersebut pertama).

jujur
sumber
7

Dengan peningkatan, Anda dapat menggunakan any_of_equal:

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

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

Anda dapat mencoba kode ini:

#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
sumber
3

Anda dapat menggunakan findfungsi, yang ditemukan di stdnamespace, yaitu std::find. Anda melewatkan std::findfungsi begindan enditerator dari vektor yang ingin Anda cari, bersama dengan elemen yang Anda cari dan membandingkan iterator yang dihasilkan dengan ujung vektor untuk melihat apakah mereka cocok atau tidak.

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

Anda juga dapat melakukan dereferensi iterator dan menggunakannya seperti biasa, seperti iterator lainnya.

TankorSmash
sumber
3

Anda dapat menggunakan hitungan juga. Ini akan mengembalikan jumlah item yang ada dalam vektor.

int t=count(vec.begin(),vec.end(),item);
Aditya
sumber
11
findlebih cepat daripada count, karena tidak terus menghitung setelah pertandingan pertama.
Camille Goudeseune
2

Jika Anda ingin menemukan string dalam vektor:

    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
sumber
2

Sampel lain menggunakan operator 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
sumber
4
Saya tidak akan merekomendasikan penyalahgunaan overloading operator sedemikian rupa.
Leon
2
Leon, aku setuju denganmu, secara semantik itu tidak benar. Saya menggunakannya untuk membuat unit test lebih jelas.
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;
}
pengguna3157855
sumber
1

(C ++ 17 ke atas):

bisa digunakan std::searchjuga

Ini juga berguna untuk mencari urutan elemen.

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

Juga ada fleksibilitas melewati beberapa algoritma pencarian. Rujuk ke sini.

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

Pavan Chandaka
sumber
1

Saya pribadi telah menggunakan template akhir-akhir ini untuk menangani beberapa jenis wadah sekaligus daripada hanya berurusan dengan vektor. Saya menemukan contoh serupa secara online (tidak ingat di mana) jadi kredit diberikan kepada siapa pun saya telah mencicilnya. Pola khusus ini tampaknya menangani array mentah juga.

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
sumber
-4

Menggunakan Newton C ++ lebih mudah, didokumentasikan sendiri dan lebih cepat daripada dengan std :: find karena mengembalikan bool secara langsung.

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

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

Saya pikir sudah jelas apa fungsinya.

include <newton/algorithm/algorithm.hpp>

if ( newton::exists_linear(first, last, value) )
   do_this();
else
   do_that();
Moises Rojo
sumber