如何找出std :: vector中是否存在项目?


616

我要做的只是检查向量中是否存在某个元素,因此我可以处理每种情况。

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

2
在向量中搜索非常慢,因为您必须查看向量的每个元素,因此如果您要进行大量查找,请考虑使用地图
naumcho

7
@naumcho:如果对向量进行了排序,则始终会进行二进制搜索,如下所示。这使得它和映射一样快,如果只存储值(不存储键/值映射),那么它将使用更少的内存。
亚当·霍斯

4
映射当然不是最佳选择,但使用set可能会有用。如果您需要O(1)查找时间,则可以使用hash_set。
菲利普

一个重复的问题给出了一个极好的答案:stackoverflow.com/a/3451045/472647
CodeMouse92 2015年

1
如果要多次搜索不同的数字,则哈希表会更有效。
NL628 '17

Answers:


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()总是必须扫描整个序列。
埃里克·马伦芬(

114
不要忘记,#include <algorithm>否则您可能会遇到非常奇怪的错误,例如“在命名空间std中找不到匹配的函数”
rustyx 2012年

80
尽管STL是“面向对象的”,但.find()它仍然不是的成员函数std::vector,您是否希望它会成为困扰它的人呢?我想知道这是否是模板的结果。
bobobobo

71
@bobobobo:OOP与成员与非成员无关。并且有一种广泛的思想流派,即如果某件事不必成为成员,或者当它以成员身份实施时没有带来任何好处,那么它就不应成为成员。std::vector<>::find()不会提供任何优势,也不需要它,因此,不,它不应成为成员。另请参见en.wikipedia.org/wiki/Coupling_%28computer_programming%29
塞巴斯蒂安·马赫

36
@phresnel我会争辩说,“当作为成员实施时,它没有任何好处”是错误的。优点是简化和更清晰的界面。例如:mvec.find(key) != mvec.cend()优于std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend()
swalog

113

正如其他人所说,使用STL findfind_if函数。但是,如果你在非常大的矢量搜索,这会影响性能,您可能要排序的载体,然后使用binary_searchlower_boundupper_bound算法。


3
好答案!查找始终为o(n)。如果与随机访问迭代器一起使用,lower_bound为o(log(n))。
斯蒂芬·埃德蒙兹

30
但是排序是O(nlogn),因此仅当您进行的搜索超过O(logn)搜索时才值得。
liori

7
@liori是的,这取决于您的使用模式。如果您只需要对它排序一次,那么反复进行多次搜索可以节省您的时间。
布莱恩·尼尔

1
@Brian Neal,如果必须进行大量元素搜索,则对大向量进行排序是值得的。如果只需要查找一次元素,则排序将为O(nlogn),而O(n)会更好:)
Swapnil B.

47

使用stl的算法标头中的find。我已经说明了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()也可能合适。它允许使用任意谓词而不是等于进行搜索。
埃里克·马林芬特

糟糕,看到您的评论为时已晚。我给出的答案也提到了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::sortqsort是向量非常低效....看到:stackoverflow.com/questions/12308243/...
贾森R.米克

1
对于较大的容器,二进制搜索的性能更好,但是对于较小的容器,简单的线性搜索可能会更快或更快速。
BillT '17

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如果您value_type从容器中使用元素类型,则可以使用1个模板参数。我添加了这样的答案。
马丁·布罗德赫斯特

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

或者,使用lambda:

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

1
bind1stbind2nd自C ++ 11弃用和在C ++ 17完全除去。使用bindplaceholders和/或lambda代替。
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从Container中提取。您需要使用typename因为Container::value_type从属名称


5
请注意,有时这有点太宽泛-例如,它可用于std :: set,但与find()成员函数相比,性能却很差。我发现它,最好使用更快的搜索(套/地图,unordered_ *)添加一个专业化集装箱
安迪Krouwel

10

请记住,如果您要进行大量查找,则可以使用STL容器来更好地进行查找。我不知道您的应用程序是什么,但是像std :: map这样的关联容器可能值得考虑。

除非您有其他原因,否则std :: vector是您选择的容器,按值查找可能就是这种原因。


即使按值查找,只要对向量进行排序并且您使用binary_search,lower_bound或upper_bound,向量也是一个不错的选择。如果容器的内容在两次查找之间更改,则vector不太好,因为需要再次排序。
Renze de Waal

8

使用STL 查找功能。

请记住,还有一个find_if函数,如果您的搜索更为复杂,也可以使用它,例如,如果您不只是在寻找元素,而是想查看是否存在满足特定条件的元素条件,例如,以“ abc”开头的字符串。(find_if将为您提供指向第一个此类元素的迭代器)。


7

使用boost可以使用any_of_equal

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

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

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

您可以使用findstd名称空间(即)中找到的函数std::find。您可以将要搜索的向量中std::findbeginand end迭代器与要查找的元素一起传递给函数,并将生成的迭代器与向量的末尾进行比较,以查看它们是否匹配。

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

您还可以取消引用该迭代器并像其他任何迭代器一样正常使用它。


3

您也可以使用count。它将返回向量中存在的项目数。

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

11
find比快count,因为它在第一场比赛后不会继续计数。
卡米尔·古德塞内

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
我不建议以这种方式滥用操作员重载。
莱昂

2
莱昂,我同意你的看法,从语义上讲这是不正确的。我用它来使单元测试更加清晰。
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及以上):

可以使用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

使用牛顿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();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.