アイテムが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 2017年

回答:


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()は1つの要素が見つかるとすぐに停止するため、count()がfind()よりも高速であることがわかりません。
エリック・マレンファント2009

114
#include <algorithm>「名前空間stdに一致する関数が見つからない」などの非常に奇妙なエラーが発生する可能性があることを忘れないでください
rustyx

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 2015

113

他の人が言ったように、STL findまたはfind_if関数を使用します。あなたは非常に大きなベクトルと、この影響を与えるパフォーマンスで検索されている場合でも、あなたはあなたのベクトルをソートし、次に使用する場合がありbinary_searchlower_boundまたはupper_boundアルゴリズムを。


3
いい答えです!Findは常にo(n)です。ランダムアクセス反復子と共に使用した場合、lower_boundはo(log(n))になります。
スティーブンエドモンズ

30
ただし、並べ替えはO(nlogn)なので、O(logn)検索よりも多くの場合にのみ価値があります。
liori 14年

7
@liori Trueは、使用パターンによって異なります。一度だけソートする必要がある場合は、何度も検索を繰り返すことで節約できます。
Brian Neal 2014年

1
@ブライアン・ニール、多くの要素検索が必要な場合、大きなベクトルをソートすることは価値があります。ソートはO(nlogn)になり、O(n)は、要素を1回だけ検索する必要がある場合に適しています:)
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()も適切な場合があります。等価ではなく任意の述語を使用して検索できます。
エリック・マレンファント2009

エラーが発生しました。私が出した答えは、find_ifにも言及しています。
フランク

39

ベクターが注文されていない場合は、MSNが提案する方法を使用してください。

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

ベクトルが順序付けられている場合は、binary_searchメソッドを使用してください。

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

二分探索はO(log n)の最悪の場合のパフォーマンスをもたらします。これは最初のアプローチよりもはるかに効率的です。バイナリ検索を使用するには、qsortを使用して最初にベクターを並べ替え、順序付けを保証することができます。


3
どういう意味std::sortですか? qsort....ベクトルに非常に非効率的ですが参照してください。stackoverflow.com/questions/12308243/...
ジェイソンR.ミック・

1
バイナリ検索は大きなコンテナーの方がパフォーマンスが良くなりますが、小さなコンテナーの場合、単純な線形検索の方が高速または高速です。
BillT 2017年

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つの
タイプ名

value_type要素タイプのコンテナーから使用する場合、@ ErikAronestyは1つのテンプレート引数で回避できます。このような答えを追加しました。
マーティンブロードハースト2016

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で除去しました。代わりにbindwith 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();
}

value_typeコンテナからを抽出できるため、1つのテンプレートパラメータで済むことに注意してください。あなたは必要とするtypenameためでContainer::value_typeある依存名


5
これは時々少し広すぎることに注意してください。たとえば、std :: setの場合は機能しますが、find()メンバー関数に比べてパフォーマンスが非常に悪くなります。より高速な検索(set / map、unordered_ *)を備えたコンテナーに特化したものを追加するのが最善の方法だ
Andy Krouwel

10

多くのルックアップを行う場合は、そのためのSTLコンテナがあることを覚えておいてください。あなたのアプリケーションが何であるかはわかりませんが、std :: mapのような連想コンテナは検討に値するかもしれません。

std :: vectorは、別の理由がない限り、最適なコンテナであり、値による検索がそのような理由になる可能性があります。


値で検索する場合でも、ベクトルがソートされていて、binary_search、lower_bound、upper_boundを使用している場合は、ベクトルを選択することをお勧めします。コンテナの内容がルックアップの間に変わる場合、再度ソートする必要があるため、ベクトルはあまり良くありません。
Renze de Waal、

8

STL 検索を使用する機能をます。

検索がより複雑な場合に使用できるfind_if関数もあることに注意してください。つまり、単に要素を探しているだけでなく、特定の条件を満たす要素があるかどうかを確認したい場合などです。たとえば、「abc」で始まる文字列。(find_if最初のそのような要素を指すイテレータを与えるでしょう)。


7

ブーストで使用できます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

名前空間にあるfind関数を使用できます。検索するベクターから関数it とイテレーターを探している要素とともに渡し、結果のイテレーターをベクターの末尾と比較して、一致するかどうかを確認します。stdstd::findstd::findbeginend

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

他のイテレータと同様に、そのイテレータを逆参照して通常どおり使用することもできます。


3

countも使用できます。これは、ベクター内に存在するアイテムの数を返します。

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

11
findcount最初の一致後はカウントし続けないため、はより高速です。
Camille Goudeseune、2015

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 2016年

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

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.