如何确定某个项目是否存在于 std::vector 中?

How to find out if an item is present in a std::vector?

提问人:Joan Venge 提问时间:2/21/2009 最后编辑:AntonioJoan Venge 更新时间:9/30/2023 访问量:1455007

问:

我想做的就是检查向量中是否存在元素,这样我就可以处理每种情况。

if ( item_present )
   do_this();
else
   do_that();
C++ 矢量 标准

评论

3赞 naumcho 2/21/2009
在向量中搜索非常慢,因为您必须查看向量的每个元素,因此如果您要进行大量查找,请考虑使用地图
7赞 Adam Hawes 2/21/2009
@naumcho:如果向量被排序,则始终有二进制搜索,如下所述。这使得它像地图一样快,如果你只存储值(而不是键/值图),那么它将使用更少的内存。
5赞 Philipp 10/8/2010
地图当然不是最佳选择,但使用 set 可能很有用。如果您需要 O(1) 查找时间,hash_set是要走的路。
1赞 NL628 11/25/2017
如果您要多次搜索不同的数字,哈希表会更有效。
1赞 Carlo Wood 2/12/2022
这个问题的答案与标题不符。我强烈建议更改标题,以便寻求给出答案的人能够找到它们。当然,这不是问这个问题的人的错,但现在我们有这种情况......无论如何,最受好评(和接受)的答案都会找到该元素(然后检查他们是否找到了它)。因此,更好的标题应该是“如何在 中查找项目,如果它存在?或者类似的东西。std::vector

答:

1189赞 MSN 2/21/2009 #1

你可以从以下位置使用 std::find :<algorithm>

#include <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()

这将返回找到的第一个元素的迭代器。如果不存在,它将迭代器返回到一个过去结束。以你为例:

#include <algorithm>
#include <vector>

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

评论

239赞 Éric Malenfant 2/21/2009
我不明白 count() 怎么会比 find() 快,因为 find() 一旦找到一个元素就会停止,而 count() 总是必须扫描整个序列。
128赞 rustyx 3/2/2012
不要忘记,否则您可能会收到非常奇怪的错误,例如“在命名空间 std 中找不到匹配的函数”#include <algorithm>
110赞 bobobobo 12/7/2012
尽管 STL 是“面向对象的”,但它仍然不是 的成员函数,正如你所期望的那样,这难道没有打扰任何人吗?我想知道这是否在某种程度上是模板化的结果。.find()std::vector
86赞 Sebastian Mach 2/4/2013
@bobobobo:OOP 与会员与非会员无关。有一种普遍的思想流派认为,如果某物不必成为成员,或者当它作为成员实施时没有任何好处时,它就不应该成为成员; 不会给任何好处,也不需要,因此,不,它不应该是会员。另请参阅 en.wikipedia.org/wiki/Coupling_%28computer_programming%29std::vector<>::find()
77赞 swalog 4/30/2015
@phresnel 我认为,“当它作为成员实施时没有带来任何好处时”在这种情况下是错误的。优点是界面更简单、更清晰。例如:比 更可取。mvec.find(key) != mvec.cend()std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend()
53赞 m-sharp 2/21/2009 #2

使用 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赞 Éric Malenfant 2/21/2009
根据 OP 的需要,find_if() 也可能是合适的。它允许使用任意谓词而不是相等进行搜索。
0赞 Frank 2/21/2009
哎呀,看到你的评论太晚了。我给出的答案也提到了find_if。
9赞 Frank 2/21/2009 #3

使用 STL 查找功能。

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

135赞 Brian Neal 2/21/2009 #4

正如其他人所说,使用 STL 查找find_if函数。但是,如果您在非常大的向量中进行搜索,这会影响性能,则可能需要对向量进行排序,然后使用 binary_searchlower_boundupper_bound 算法。

评论

3赞 Stephen Edmonds 7/9/2009
好答案!Find 始终为 o(n)。如果与随机访问迭代器一起使用,则lower_bound为 o(log(n))。
52赞 liori 6/15/2014
不过,排序是 O(nlogn),因此只有当您做的不仅仅是 O(logn) 搜索时才有价值。
11赞 Brian Neal 6/18/2014
@liori 没错,这取决于您的使用模式。如果你只需要对它进行一次排序,然后反复进行多次搜索,它可以节省你。
1赞 Swapnil B. 3/12/2018
@Brian Neal,如果必须对一个大向量进行许多元素搜索,那么对它进行排序是值得的。排序将是 O(nlogn),如果只需要找到一个元素一次,则 O(n) 会更好:)
0赞 Brice M. Dempsey 8/18/2020
请注意,这可能会对您的分支预测造成严重破坏。
11赞 David Thornley 2/21/2009 #5

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

std::vector 是首选的容器,除非您有另一个原因,而按值查找可能就是这样的原因。

评论

0赞 Renze de Waal 2/21/2009
即使按值查找,向量也是一个不错的选择,只要它是排序的,并且您使用 binary_search、lower_bound或upper_bound。如果容器的内容在查找之间发生变化,则 vector 不是很好,因为需要再次排序。
6赞 TrungTN 4/28/2012 #6

您可以尝试以下代码:

#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()
}
59赞 spiralmoon 11/23/2012 #7

如果您的向量未排序,请使用 MSN 建议的方法:

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

如果你的向量是有序的,请使用Brian Neal建议binary_search方法:

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

二进制搜索产生 O(log n) 最坏情况的性能,这比第一种方法更有效。为了使用二进制搜索,您可以先使用 qsort 对向量进行排序,以确保它是有序的。

评论

4赞 Jason R. Mick 8/16/2013
你不是说吗? 在向量上效率非常低......参见:stackoverflow.com/questions/12308243/...std::sortqsort
1赞 BillT 3/31/2017
二进制搜索对于较大的容器会表现得更好,但对于较小的容器,简单的线性搜索可能会更快,甚至更快。
0赞 einpoklum 1/10/2022
@BillT:一个像样的二进制搜索实现难道不会在某个元素阈值以下切换到线性搜索吗?
0赞 Gank 5/31/2013 #8

如果要在向量中查找字符串:

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

评论

1赞 einpoklum 1/10/2022
std::find在这种情况下就好了,不需要谓词对象。
24赞 Andy Krouwel 9/5/2013 #9

我用这样的东西......

#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

...因为这样一来,它实际上清晰易读。 (显然,您可以在多个位置重复使用模板)。

评论

0赞 Erik Aronesty 3/3/2015
您可以使用 2 种类型名使其适用于列表或向量
0赞 2/12/2016
@ErikAronesty,如果您将 from 容器用于元素类型,则可以摆脱 1 个模板参数。我添加了这样的答案。value_type
7赞 Charles Gueunet 10/8/2020
你基本上是在写:。该方法可以是一行:if true return true else return falsereturn std::find(Vec.begin(), Vec.end(), Element) != Vec.end();
4赞 user3157855 1/27/2014 #10
template <typename T> bool IsInVector(const T & what, const std::vector<T> & vec)
{
    return std::find(vec.begin(),vec.end(),what)!=vec.end();
}

评论

0赞 einpoklum 1/10/2022
如果你想适应容器,那就通用地做,而不仅仅是一个向量。也许称它为什么或什么。std::find()find()stdx::find()
5赞 TankorSmash 6/15/2014 #11

您可以使用在命名空间中找到的 find 函数,即 .从要搜索的向量中传递函数 和 迭代器,以及要查找的元素,并将生成的迭代器与向量的末尾进行比较,以查看它们是否匹配。stdstd::findstd::findbeginend

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

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

4赞 Aditya 3/11/2015 #12

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

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

评论

13赞 Camille Goudeseune 8/17/2015
find比 快,因为它不会在第一场比赛后继续计数。count
29赞 Deqing 8/11/2015 #13

在 C++11 中,您可以使用 .例如,如果它是 then:any_ofvector<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();

评论

2赞 andreee 4/30/2019
bind1st并且自 C++ 11 起被弃用,并在 C++17 中完全删除。请改用 and/或 lambda。bind2ndbindplaceholders
4赞 einpoklum 1/10/2022
当我们有的时候为什么要使用?std::any_of()std::find()
2赞 Bex 3/25/2022
如果目的只是为了检查会员资格,为什么在我们有的时候使用?std::find()std::any_of
1赞 Maf 2/10/2023
@einpoklum std::find 仅适用于 C++20。并非所有项目都已经在使用 C++20。不要以为将大型专业项目从一个版本迁移到另一个版本是那么容易。相信我。
1赞 einpoklum 2/10/2023
@Maf:公平地说,我有一种错觉,认为它更老了。
15赞 user325117 2/12/2016 #14

下面是一个适用于任何容器的函数:

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 个模板参数,因为您可以从容器中提取 。您需要 because 是一个依赖名称value_typetypenameContainer::value_type

评论

5赞 Andy Krouwel 11/2/2016
请注意,这有时有点太宽泛了 - 例如,它适用于 std::set,但与 find() 成员函数相比,性能很差。我发现最好通过更快的搜索(set/map,unordered_*)为容器添加专业化
1赞 underscore_d 7/2/2020
也许有一天他们最终会把它添加到 stdlib 中......而不是人们不得不一遍又一遍地问如何重新发明这样一个小轮子。现在在 C++20 中,我们完全可行,所以可以直接调用而不是 ,Bob 是你的叔叔。rangesRangeContainer
0赞 einpoklum 1/10/2022
您如何看待@PascalLaferrière推导价值类型的方法
10赞 Mikhail 9/28/2016 #15

使用 boost,您可以使用any_of_equal

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

bool item_present = boost::algorithm::any_of_equal(vector, element);
2赞 Pavan Chandaka 3/27/2019 #16

(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

评论

2赞 einpoklum 1/10/2022
std::search 用于搜索范围内的多个值中的任何一个;对于单个值,没有理由使用它。
3赞 Pascal Laferrière 10/28/2019 #17

我个人最近使用模板来一次处理多种类型的容器,而不是只处理向量。我在网上找到了一个类似的例子(不记得在哪里),所以功劳归于我从谁那里偷来的。这种特殊的模式似乎也处理原始数组。

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

评论

0赞 einpoklum 1/10/2022
请考虑将值-类型-演绎逻辑分离到它自己的特征中,例如template <typename Container> struct value_type { ... etc. ... }
0赞 Pascal Laferrière 2/8/2022
@einpoklum我对模板逻辑很陌生,老实说,我几乎无法理解这个解决方案是如何发挥其魔力的。你能扩展一下{...等等...}?
11赞 Pavan Chandaka 7/3/2022 #18

从 C++20 开始,使用范围 (#include <ranges>)

    //SAMPLE DATA
    std::vector<int> vecOfElements = { 2,4,6,8 };

    //DO SOMETHING IF 8 IN VECTOR
    if (std::ranges::find(vecOfElements, 8) != vecOfElements.end())
    {
        std::cout << "DO SOMETHING" << std::endl;
    }
0赞 BullyWiiPlaza 3/16/2023 #19

另一种方法是使用 std::count

示例代码:

#include <algorithm>
#include <vector>

void run_vector_contains_example() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    int item_to_find = 3;

    int count = std::count(vec.begin(), vec.end(), item_to_find);

    if (count > 0) {
        // item found in vector
    } else {
        // item not found in vector
    }
}

诚然,这种方法可能比处理大型向量时慢。std::find

评论

0赞 Cedric Martens 10/6/2023
你为什么要用这个而不是查找?
5赞 Mikhail 9/30/2023 #20

在 C++23 中,我们终于有了最明显的解决方案

if (std::ranges::contains(vec, item))
   do_this();
else
   do_that();

评论

0赞 ABaumstumpf 9/30/2023
是的 - 最后。可惜的是,委员会长期以来一直抵制人们建议我们只需要一个“有”或“包含”的容器功能。std::map 只包含 C++20,对矢量没有爱。