Làm thế nào để tìm hiểu xem một mục có trong std :: vector không?


616

Tất cả những gì tôi muốn làm là kiểm tra xem một phần tử có tồn tại trong vectơ hay không, vì vậy tôi có thể xử lý từng trường hợp.

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

2
tìm kiếm trong một vectơ rất chậm vì bạn phải xem xét từng yếu tố của vectơ, vì vậy hãy cân nhắc sử dụng bản đồ nếu bạn đang thực hiện nhiều tra cứu
naumcho

7
@naumcho: Nếu vectơ được sắp xếp luôn có tìm kiếm nhị phân, như được đăng dưới đây. Điều này làm cho nó nhanh như bản đồ và nếu bạn chỉ lưu trữ các giá trị (không phải bản đồ khóa / giá trị) thì nó sẽ sử dụng ít bộ nhớ hơn.
Adam Hawes

4
bản đồ chắc chắn không phải là sự lựa chọn tốt nhất, nhưng sử dụng bộ có thể hữu ích. Nếu bạn cần thời gian tra cứu O (1), hash_set là cách tốt nhất.
Phi

Một câu trả lời tuyệt vời hiện trên một câu hỏi trùng lặp: stackoverflow.com/a/3451045/472647
CodeMouse92

1
Nếu bạn sẽ tìm kiếm nhiều lần cho các số khác nhau, một bảng băm sẽ hiệu quả hơn.
NL628

Câu trả lời:


915

Bạn có thể sử dụng std::findtừ <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()

Điều này trả về một bool ( truenếu có, falsenếu không). Với ví dụ của bạn:

#include <algorithm>
#include <vector>

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

216
Tôi không thấy cách đếm () có thể nhanh hơn find (), vì find () dừng ngay khi tìm thấy một phần tử, trong khi Count () luôn phải quét toàn bộ chuỗi.
Éric Malenfant

114
Đừng quên #include <algorithm>hoặc nếu không bạn có thể gặp các lỗi rất lạ như 'không thể tìm thấy chức năng khớp trong không gian tên std'
rustyx

80
Có phải ai cũng không bận tâm rằng mặc dù STL là "hướng đối tượng", .find()vẫn không phải là một chức năng thành viên std::vector, như bạn mong đợi? Tôi tự hỏi nếu đây là một hậu quả của templating.
bobobobo

71
@bobobobo: OOP không liên quan gì đến thành viên so với người không phải thành viên. Và có một trường phái rộng rãi về suy nghĩ rằng nếu một cái gì đó không phải là thành viên, hoặc khi nó không mang lại bất kỳ lợi thế nào khi được thực hiện như một thành viên, thì nó không nên là một thành viên; std::vector<>::find()sẽ không cung cấp bất kỳ lợi thế nào, cũng không cần thiết, do đó, không, nó không nên là một thành viên. Xem thêm en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach

36
@phresnel Tôi sẽ lập luận rằng "khi nó không mang lại bất kỳ lợi thế nào khi được thực hiện như một thành viên" là sai đối với trường hợp này. Ưu điểm là giao diện đơn giản và rõ ràng hơn. Ví dụ: mvec.find(key) != mvec.cend()thích hợp hơn std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog

113

Như những người khác đã nói, sử dụng STL findhoặc các find_ifchức năng. Nhưng nếu bạn đang tìm kiếm theo vectơ rất lớn và hiệu suất tác động này, bạn có thể muốn sắp xếp vector của bạn và sau đó sử dụng binary_search, lower_boundhoặc upper_boundcác thuật toán.


3
Câu trả lời tốt! Tìm luôn là o (n). low_bound là o (log (n)) nếu được sử dụng với các trình vòng lặp truy cập ngẫu nhiên.
Stephen Edmonds

30
Sắp xếp là O (nlogn), vì vậy chỉ có giá trị nếu bạn thực hiện nhiều hơn tìm kiếm O (logn).
liori

7
@liori Đúng nó phụ thuộc vào cách sử dụng của bạn. Nếu bạn chỉ cần sắp xếp nó một lần, sau đó liên tục thực hiện nhiều tìm kiếm, nó có thể giúp bạn tiết kiệm.
Brian Neal

1
@Brian Neal, sắp xếp một vectơ lớn có giá trị nếu phải có nhiều phần tử tìm kiếm trên đó. Sắp xếp sẽ là O (nlogn) và O (n) sẽ tốt hơn nếu người ta chỉ phải tìm một phần tử một lần :)
Swapnil B.

47

Sử dụng find từ tiêu đề thuật toán của stl. Tôi đã minh họa việc sử dụng nó với kiểu int. Bạn có thể sử dụng bất kỳ loại nào bạn thích miễn là bạn có thể so sánh về sự bình đẳng (quá tải == nếu bạn cần cho lớp tùy chỉnh của mình).

#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
Tùy thuộc vào nhu cầu của OP, find_if () cũng có thể phù hợp. Nó cho phép tìm kiếm bằng cách sử dụng một vị từ tùy ý thay vì bình đẳng.
Éric Malenfant

Rất tiếc, đã thấy nhận xét của bạn quá muộn. Câu trả lời tôi cũng đề cập đến find_if.
Frank

39

Nếu vectơ của bạn không được đặt hàng, hãy sử dụng phương pháp MSN đề xuất:

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

Nếu vector của bạn được đặt hàng, hãy sử dụng phương thức binary_search Brian Neal đề xuất:

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

tìm kiếm nhị phân mang lại hiệu suất trong trường hợp xấu nhất O (log n), hiệu quả hơn so với cách tiếp cận đầu tiên. Để sử dụng tìm kiếm nhị phân, bạn có thể sử dụng qsort để sắp xếp vectơ trước để đảm bảo nó được đặt hàng.


3
Ý bạn là std::sortsao? qsortrất không hiệu quả trên các vectơ .... xem: stackoverflow.com/questions/12308243/ Kẻ
Jason R. Mick

1
Tìm kiếm nhị phân sẽ hoạt động tốt hơn đối với các container lớn hơn, nhưng đối với các container nhỏ, tìm kiếm tuyến tính đơn giản có thể sẽ nhanh hoặc nhanh hơn.
BillT

21

Tôi sử dụng một cái gì đó như thế này ...

#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

... theo cách đó nó thực sự rõ ràng và dễ đọc. (Rõ ràng bạn có thể sử dụng lại mẫu ở nhiều nơi).


và bạn có thể làm cho nó hoạt động cho danh sách hoặc vectơ bằng cách sử dụng 2 kiểu chữ
Erik Aronesty

@ErikAronesty bạn có thể thoát khỏi 1 đối số mẫu nếu bạn sử dụng value_typetừ vùng chứa cho loại phần tử. Tôi đã thêm một câu trả lời như thế này.
Martin Broadhurst

13

Trong C ++ 11 bạn có thể sử dụng any_of. Ví dụ: nếu là vector<string> v;thì:

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

Ngoài ra, sử dụng lambda:

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

1
bind1stkhôngbind2nd được dùng nữa kể từ C ++ 11 và bị loại bỏ hoàn toàn trong C ++ 17. Sử dụng bindvới placeholdersvà / hoặc lambdas thay thế.
andreee

11

Đây là một chức năng sẽ hoạt động cho bất kỳ Container nào:

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

Lưu ý rằng bạn có thể thoát khỏi 1 tham số mẫu vì bạn có thể trích xuất value_typetừ Container. Bạn cần typenamebởi vì Container::value_typelà một tên phụ thuộc .


5
Lưu ý rằng điều này đôi khi hơi quá rộng - chẳng hạn, nó hoạt động với std :: set, nhưng cho hiệu năng khủng so với hàm thành viên find (). Tôi đã tìm thấy cách tốt nhất để thêm chuyên môn hóa cho các container với tìm kiếm nhanh hơn (bộ / bản đồ, không có thứ
tự_

10

Hãy nhớ rằng, nếu bạn sẽ thực hiện nhiều tra cứu, có những thùng chứa STL tốt hơn cho việc đó. Tôi không biết ứng dụng của bạn là gì, nhưng các thùng chứa liên kết như std :: map có thể đáng xem xét.

std :: vector là nơi chứa sự lựa chọn trừ khi bạn có lý do cho việc khác và việc tra cứu theo giá trị có thể là một lý do như vậy.


Ngay cả với tra cứu theo giá trị, vectơ có thể là một lựa chọn tốt, miễn là nó được sắp xếp và bạn sử dụng binary_search, low_bound hoặc Upper_bound. Nếu nội dung của container thay đổi giữa các lần tra cứu, vectơ không tốt lắm vì cần phải sắp xếp lại.
Renze de Waal

8

Sử dụng tìm STL chức năng .

Hãy nhớ rằng cũng có một hàm find_if , bạn có thể sử dụng nếu tìm kiếm của bạn phức tạp hơn, tức là nếu bạn không chỉ tìm kiếm một phần tử, nhưng, ví dụ, muốn xem liệu có một phần tử nào đó đáp ứng một số phần nhất định không điều kiện, ví dụ, một chuỗi bắt đầu bằng "abc". ( find_ifsẽ cung cấp cho bạn một trình vòng lặp trỏ đến phần tử đầu tiên như vậy).


7

Với boost bạn có thể sử dụng any_of_equal:

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

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

5

Bạn có thể thử mã này:

#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

Bạn có thể sử dụng findhàm, được tìm thấy trong stdkhông gian tên, nghĩa là std::find. Bạn truyền std::findhàm beginenditerator từ vectơ bạn muốn tìm kiếm, cùng với phần tử bạn đang tìm và so sánh iterator kết quả với phần cuối của vectơ để xem chúng có khớp hay không.

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

Bạn cũng có thể hủy bỏ trình lặp đó và sử dụng nó như bình thường, giống như bất kỳ trình vòng lặp nào khác.


3

Bạn có thể sử dụng đếm quá. Nó sẽ trả về số lượng vật phẩm có trong một vectơ.

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

11
findnhanh hơn count, bởi vì nó không tiếp tục đếm sau trận đấu đầu tiên.
Camille Goudeseune

2

Nếu bạn muốn tìm một chuỗi trong một vectơ:

    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

Một mẫu khác sử dụng toán tử 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
Tôi không khuyên bạn nên lạm dụng quá tải toán tử theo cách như vậy.
Leon

2
Leon, tôi đồng ý với bạn, về mặt ngữ nghĩa thì không đúng. Tôi sử dụng nó để làm cho bài kiểm tra đơn vị rõ ràng hơn.
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 trở lên):

có thể sử dụng std::searchcũng

Điều này cũng hữu ích cho việc tìm kiếm chuỗi các yếu tố.

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

Ngoài ra có sự linh hoạt của việc vượt qua một số thuật toán tìm kiếm. Tham khảo tại đây.

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


1

Cá nhân tôi đã sử dụng các mẫu trễ để xử lý nhiều loại container cùng một lúc thay vì chỉ xử lý các vectơ. Tôi đã tìm thấy một ví dụ tương tự trực tuyến (không thể nhớ ở đâu) vì vậy tín dụng dành cho bất cứ ai tôi đã lấy từ này. Mẫu đặc biệt này dường như cũng xử lý các mảng thô.

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

Sử dụng Newton C ++, nó dễ dàng hơn, tự ghi lại và nhanh hơn so với std :: find vì trả về một bool trực tiếp.

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

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

Tôi nghĩ rõ ràng những gì các chức năng làm.

include <newton/algorithm/algorithm.hpp>

if ( newton::exists_linear(first, last, value) )
   do_this();
else
   do_that();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.