จะทราบได้อย่างไรว่ารายการนั้นมีอยู่ใน std :: vector หรือไม่?


616

สิ่งที่ฉันต้องการทำคือการตรวจสอบว่ามีองค์ประกอบอยู่ในเวกเตอร์หรือไม่ดังนั้นฉันจึงสามารถจัดการกับแต่ละกรณีได้

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

2
ค้นหาในเวกเตอร์ช้ามากเพราะคุณต้องมองไปที่องค์ประกอบเดียวทุกเวกเตอร์เพื่อพิจารณาการใช้แผนที่ถ้าคุณกำลังทำมากของการค้นหา
naumcho

7
@naumcho: หากมีการจัดเรียงเวกเตอร์จะมีการค้นหาแบบไบนารีเสมอดังที่โพสต์ด้านล่าง สิ่งนี้ทำให้เร็วเท่ากับแผนที่และถ้าคุณเก็บค่าไว้เท่านั้น (ไม่ใช่แผนที่คีย์ / ค่า) ก็จะใช้หน่วยความจำน้อยลง
Adam Hawes

4
แผนที่ไม่ใช่ทางเลือกที่ดีที่สุด แต่การใช้ชุดอาจมีประโยชน์ หากคุณต้องการเวลาในการค้นหา O (1) hash_set คือหนทางที่จะไป
Philipp

คำตอบที่ยอดเยี่ยมนำเสนอในคำถามที่ซ้ำกัน: stackoverflow.com/a/3451045/472647
CodeMouse92

1
หากคุณกำลังค้นหาตัวเลขหลายครั้งด้วยกันตารางแฮชจะมีประสิทธิภาพมากกว่า
NL628

คำตอบ:


915

คุณสามารถใช้std::findจาก<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()

สิ่งนี้จะคืนค่าบูล ( trueถ้ามีเป็นfalseอย่างอื่น) ด้วยตัวอย่างของคุณ:

#include <algorithm>
#include <vector>

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

216
ฉันไม่เห็นว่า count () จะเร็วกว่า find () ได้อย่างไรเนื่องจาก find () หยุดทันทีที่พบหนึ่งองค์ประกอบในขณะที่ count () ต้องสแกนลำดับทั้งหมดเสมอ
Éric Malenfant

114
อย่าลืม#include <algorithm>มิฉะนั้นคุณอาจได้รับข้อผิดพลาดแปลก ๆ เช่น 'ไม่สามารถหาฟังก์ชั่นการจับคู่ในเนมสเปซ std' ได้
rustyx

80
มันไม่รบกวนใครเลยแม้จะมี STL ที่เป็น "object-oriented" แต่.find()ก็ยังไม่ได้เป็นฟังก์ชันของสมาชิกstd::vectorอย่างที่คุณคาดหวัง ฉันสงสัยว่านี่จะเป็นผลมาจากการทำให้อุณหภูมิลดลง
bobobobo

71
@bobobobo: OOP ไม่มีส่วนเกี่ยวข้องกับสมาชิกและไม่ใช่สมาชิก และมีโรงเรียนแห่งความคิดที่แพร่หลายว่าหากบางสิ่งบางอย่างไม่จำเป็นต้องเป็นสมาชิกหรือเมื่อมันไม่ได้ให้ประโยชน์ใด ๆ เมื่อดำเนินการในฐานะสมาชิกมากกว่าที่มันไม่ควรเป็นสมาชิก std::vector<>::find()จะไม่ให้ประโยชน์ใด ๆ และไม่จำเป็นดังนั้นจึงไม่ควรเป็นสมาชิก ดูเพิ่มเติมen.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach

36
@phresnel ฉันจะยืนยันว่า "เมื่อมันไม่ให้ประโยชน์ใด ๆ เมื่อดำเนินการในฐานะสมาชิก" เป็นเท็จสำหรับกรณีนี้ ข้อดีคือเป็นอินเทอร์เฟซที่เรียบง่ายและชัดเจน ตัวอย่างเช่นเป็นที่นิยมmvec.find(key) != mvec.cend() std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend()
swalog

113

อย่างที่คนอื่นพูดใช้ STL findหรือfind_ifฟังก์ชั่น แต่ถ้าคุณกำลังค้นหาในเวกเตอร์ขนาดใหญ่มากและส่งผลกระทบต่อประสิทธิภาพการทำงานนี้คุณอาจต้องการที่จะเรียงลำดับเวกเตอร์ของคุณแล้วใช้binary_search, lower_boundหรือupper_boundอัลกอริทึม


3
คำตอบที่ดี! ค้นหาอยู่เสมอ (n) lower_bound คือ o (log (n)) หากใช้กับตัววนซ้ำแบบเข้าถึงได้
สตีเฟ่น Edmonds

30
แม้ว่าการเรียงลำดับคือ O (nlogn) ดังนั้นจึงคุ้มค่าเฉพาะเมื่อคุณทำการค้นหามากกว่า O (logn)
liori

7
@liori จริงขึ้นอยู่กับรูปแบบการใช้งานของคุณ หากคุณต้องการเรียงลำดับครั้งเดียวจากนั้นทำการค้นหาหลาย ๆ ครั้งที่สามารถช่วยคุณได้
Brian Neal

1
@Brian Neal การเรียงลำดับเวกเตอร์ขนาดใหญ่นั้นมีค่าถ้าต้องมีการค้นหาองค์ประกอบหลายรายการ การเรียงลำดับจะเป็น O (nlogn) และ O (n) จะดีกว่าหากมีการค้นหาองค์ประกอบเพียงครั้งเดียว :)
Swapnil B.

47

ใช้ค้นหาจากส่วนหัวอัลกอริทึมของ stl ฉันได้แสดงให้เห็นถึงการใช้งานกับชนิด int คุณสามารถใช้ประเภทใดก็ได้ที่คุณต้องการตราบใดที่คุณสามารถเปรียบเทียบความเท่าเทียมกันได้ (เกิน == ถ้าคุณต้องการสำหรับคลาสที่กำหนดเองของคุณ)

#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, find_if () อาจเหมาะสม จะช่วยให้การค้นหาโดยใช้คำกริยาโดยพลการแทนความเท่าเทียมกัน
Éric Malenfant

อ๊ะเห็นความคิดเห็นของคุณสายเกินไป คำตอบที่ฉันให้ไว้ยังกล่าวถึง find_if
Frank

39

หากไม่มีการสั่งซื้อเวกเตอร์ให้ใช้วิธีที่ MSN แนะนำ:

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

หากมีการสั่งซื้อเวกเตอร์ของคุณให้ใช้วิธี binary_search แนะนำ Brian Neal:

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

การค้นหาแบบไบนารีให้ผลการทำงาน O (log n) ที่แย่ที่สุดซึ่งเป็นวิธีที่มีประสิทธิภาพมากกว่าวิธีแรก ในการใช้การค้นหาแบบไบนารีคุณอาจใช้ qsort เพื่อจัดเรียงเวกเตอร์ก่อนเพื่อรับประกันว่าจะได้รับคำสั่ง


3
คุณไม่หมายถึงstd::sortเหรอ qsortไม่มีประสิทธิภาพในเวกเตอร์ .... ดู: stackoverflow.com/questions/12308243/…
Jason R. Mick

1
การค้นหาแบบไบนารี่จะทำงานได้ดีกว่าสำหรับตู้คอนเทนเนอร์ขนาดใหญ่ แต่สำหรับตู้คอนเทนเนอร์ขนาดเล็กการค้นหาแบบเชิงเส้นอย่างง่ายน่าจะเร็วหรือเร็วกว่า
BillT

21

ฉันใช้สิ่งนี้ ...

#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

... ด้วยวิธีการที่ชัดเจนและอ่านได้จริง (เห็นได้ชัดว่าคุณสามารถใช้แม่แบบซ้ำได้หลายที่)


และคุณสามารถทำให้มันเป็นรายการหรือเวกเตอร์ได้โดยใช้ 2 ชื่อไฟล์
Erik Aronesty

@ErikAronesty คุณสามารถใช้อาร์กิวเมนต์ 1 เทมเพลตถ้าคุณใช้value_typeจากคอนเทนเนอร์สำหรับประเภทองค์ประกอบ ฉันได้เพิ่มคำตอบเช่นนี้
Martin Broadhurst

13

ใน C ++ 11 any_ofคุณสามารถใช้ ตัวอย่างเช่นถ้ามันเป็นvector<string> v;แล้ว:

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

หรือใช้แลมบ์ดา:

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

1
bind1stและbind2ndจะเลิกตั้งแต่ C ++ 11และลบออกอย่างสมบูรณ์ใน C ++ 17 ใช้bindกับplaceholdersและ / หรือ lambdas แทน
andreee

11

นี่คือฟังก์ชั่นที่ใช้งานได้กับคอนเทนเนอร์ใด ๆ :

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

โปรดทราบว่าคุณสามารถไปด้วยพารามิเตอร์เทมเพลต 1 เนื่องจากคุณสามารถแยกvalue_typeจากคอนเทนเนอร์ คุณต้องการtypenameเพราะContainer::value_typeเป็นชื่อที่ขึ้นต่อกัน


5
โปรดทราบว่าบางครั้งมันกว้างเกินไปสักหน่อย - มันใช้งานได้กับ std :: set แต่ให้ประสิทธิภาพที่แย่มากเมื่อเทียบกับฟังก์ชั่นสมาชิก find () ฉันพบว่าการเพิ่มความเชี่ยวชาญสำหรับคอนเทนเนอร์ด้วยการค้นหาที่รวดเร็วกว่า (ชุด / แผนที่, ไม่มีการจัด
อันดับ _

10

โปรดจำไว้ว่าหากคุณกำลังทำการค้นหาจำนวนมากมี STL container ที่ดีกว่า ฉันไม่ทราบว่าแอปพลิเคชันของคุณคืออะไร แต่คอนเทนเนอร์ที่เชื่อมโยงเช่น std :: map อาจมีมูลค่าการพิจารณา

std :: vector เป็นที่เก็บของตัวเลือกเว้นแต่คุณจะมีเหตุผลสำหรับสิ่งอื่นและการค้นหาตามค่าอาจเป็นเหตุผลดังกล่าว


แม้ว่าการค้นหาตามค่าเวกเตอร์อาจเป็นตัวเลือกที่ดีตราบใดที่มีการจัดเรียงและคุณใช้ binary_search, lower_bound หรือ upper_bound หากเนื้อหาของคอนเทนเนอร์เปลี่ยนแปลงระหว่างการค้นหาเวกเตอร์จะไม่ดีมากเนื่องจากต้องเรียงลำดับอีกครั้ง
Renze de Waal

8

ใช้ STL ค้นหาฟังก์ชั่น

โปรดทราบว่านอกจากนี้ยังมีฟังก์ชั่นfind_ifซึ่งคุณสามารถใช้หากการค้นหาของคุณมีความซับซ้อนมากขึ้นเช่นหากคุณไม่ได้มองหาองค์ประกอบเพียงอย่างเดียว แต่ต้องการดูว่ามีองค์ประกอบที่เติมเต็มแน่นอนหรือไม่ เงื่อนไขตัวอย่างเช่นสตริงที่ขึ้นต้นด้วย "abc" ( find_ifจะให้ตัววนซ้ำที่ชี้ไปยังองค์ประกอบดังกล่าวแรก)



5

คุณสามารถลองรหัสนี้:

#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

คุณสามารถใช้findฟังก์ชั่นที่พบในstdnamespace std::findคือ คุณผ่านstd::findฟังก์ชั่นbeginและตัวendวนซ้ำจากเวกเตอร์ที่คุณต้องการค้นหาพร้อมกับองค์ประกอบที่คุณกำลังมองหาและเปรียบเทียบตัววนซ้ำผลลัพธ์ไปยังจุดสิ้นสุดของเวกเตอร์เพื่อดูว่าตรงกันหรือไม่

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

คุณยังสามารถอ่านค่าตัววนซ้ำและใช้งานได้ตามปกติเหมือนตัววนซ้ำอื่น ๆ


3

คุณสามารถใช้การนับได้เช่นกัน มันจะคืนจำนวนรายการที่มีอยู่ในเวกเตอร์

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

11
findเร็วกว่าcountเพราะมันไม่นับต่อไปหลังจากการแข่งขันครั้งแรก
Camille Goudeseune

2

หากคุณต้องการหาสตริงในเวกเตอร์:

    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 ++

#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
ฉันจะไม่แนะนำการใช้โอเปอเรเตอร์ที่ใช้งานหนักเกินไปในลักษณะนี้
Leon

2
Leon, ฉันเห็นด้วยกับคุณ, ความหมายมันไม่ถูกต้อง ฉันใช้มันเพื่อทำให้การทดสอบหน่วยชัดเจนขึ้น
Valdemar_Rudolfovich


1

(C ++ 17 ขึ้นไป):

สามารถใช้ std::searchยัง

สิ่งนี้ยังมีประโยชน์สำหรับการค้นหาลำดับขององค์ประกอบ

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

นอกจากนี้ยังมีความยืดหยุ่นในการผ่านอัลกอริทึมการค้นหาบางอย่าง อ้างอิงที่นี่

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


1

ฉันใช้เท็มเพลตล่าช้าเพื่อจัดการคอนเทนเนอร์หลายชนิดในคราวเดียวแทนที่จะจัดการกับเวกเตอร์เท่านั้น ฉันพบตัวอย่างที่คล้ายกันออนไลน์ (จำไม่ได้ว่าอยู่ที่ไหน) ดังนั้นเครดิตจะไปที่ใครก็ตามที่ฉันเคยขโมยจาก รูปแบบนี้โดยเฉพาะดูเหมือนว่าจะจัดการอาร์เรย์ดิบเช่นกัน

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 ++ง่ายกว่าทำเอกสารด้วยตนเองและเร็วกว่า std :: find เนื่องจากคืนค่าบูลโดยตรง

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

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

ฉันคิดว่ามันชัดเจนว่าฟังก์ชั่นทำอะไร

include <newton/algorithm/algorithm.hpp>

if ( newton::exists_linear(first, last, value) )
   do_this();
else
   do_that();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.