2009-02-20 5 views
460

Все, что я хочу сделать, это проверить, существует ли элемент в векторе или нет, поэтому я могу иметь дело с каждым случаем.Как узнать, присутствует ли элемент в std :: vector?

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

поиск в векторе очень медленно, так как вы должны смотреть на каждый элемент вектора так, рассмотреть возможность использования карты, если вы делаете много поисков – naumcho

+6

@naumcho: Если вектор отсортирован, всегда есть двоичный поиск, как показано ниже. Это делает его так же быстро, как карта, и если вы только сохраняете значения (не карты ключей/значений), тогда он будет использовать намного меньше памяти. Карты –

+2

, конечно, не самый лучший выбор, но использование набора может оказаться полезным. Если вам нужно O (1) время поиска, hash_set - это путь. – Philipp

ответ

689

Вы можете использовать std::find из <algorithm>:

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

Это возвращает логическое значение (true, если присутствует, в противном случае false). В вашем примере:

#include <algorithm> 

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

Используя std :: count вместо (std :: count (...)> 0), было бы «быстрее в теории»? – Klaim

+8

Возможно. Это зависит от того, как часто вы ищете пустые векторы. – MSN

+187

Я не вижу, как count() может быть быстрее, чем find(), так как find() останавливается, как только один элемент найден, а count() всегда должен сканировать всю последовательность. –

41

Использовать поиск из заголовка алгоритма stl.Я проиллюстрировал его использование с использованием типа int. Вы можете использовать любой тип, который вам нравится, пока вы можете сравнить для равенства (перегрузка ==, если вам нужно для своего пользовательского класса).

+2

В зависимости от потребностей OP, find_if() также может быть уместным. Он позволяет искать с использованием произвольного предиката вместо равенства. –

+0

К сожалению, ваш комментарий слишком поздно. Ответ, который я дал, также упоминает find_if. – Frank

7

Используйте функцию STL find.

Помните, что существует также функция find_if, которую вы можете использовать, если ваш поиск сложнее, т.е. если вы ищете не только элемент, но, например, хотите увидеть, есть ли элемент который выполняет определенное условие, например, строку, начинающуюся с «abc». (find_if даст вам итератор, который указывает на первый такой элемент).

94

Как уже говорилось, используйте функции STL find или find_if. Но если вы ищете очень большие векторы, и это влияет на производительность, вы можете отсортировать свой вектор, а затем использовать алгоритмы, lower_bound или upper_bound.

+2

Найти всегда o (n). lower_bound is o (log (n)), если используется с итераторами с произвольным доступом. –

+16

Сортировка O (nlogn), хотя, только если вы выполняете поиск более O (logn). – liori

+4

@liori Правда, это зависит от ваших шаблонов использования. Если вам нужно только отсортировать его один раз, затем многократно выполняет много поисков, которые он может сэкономить. –

9

Имейте в виду, что если вы собираетесь делать много поисков, есть контейнеры STL, которые лучше для этого. Я не знаю, что ваше приложение, но ассоциативные контейнеры, такие как std :: map, заслуживают рассмотрения.

std :: vector - это контейнер выбора, если у вас нет причины для другого, и поиск по значению может быть такой причиной.

+0

Даже при поиске по значению вектор может быть хорошим выбором, если он отсортирован, и вы используете binary_search, lower_bound или upper_bound.Если содержимое контейнера изменяется между поиском, вектор не очень хорош из-за необходимости снова сортировать. –

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

Если вектор не упорядочен, использовать подход 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' очень неэффективен для векторов .... см .: http://stackoverflow.com/questions/12308243/trying-to-use-qsort-with-vector –

+0

Двоичный поиск будет работать лучше для больших контейнеров, но для небольшие контейнеры, простой линейный поиск, вероятно, будет таким же быстрым или быстрым. – BillT

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

я использую что-то вроде этого ...

#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

, и вы можете заставить его работать для списков или векторов, используя 2 typenames –

+0

@ErikAronesty вы можете уйти с 1 аргументом шаблона, если вы используете 'value_type' из контейнера для типа элемента. Я добавил такой ответ. –

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

Вы можете использовать функцию find, найденную в std пространстве имен, т.е. std::find. Вы передаете функцию std::findbegin и end итератору из вектора, который хотите найти, вместе с элементом, который вы ищете, и сравните полученный итератор с концом вектора, чтобы узнать, соответствуют ли они или нет.

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

Вы также можете разыменовать этот итератор и использовать его как обычно, как и любой другой итератор.

3

Вы также можете использовать счет. Он вернет количество элементов, имеющихся в векторе.

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

'find' быстрее, чем' count', потому что он не продолжает подсчитывать после первого совпадения. –

6

В C++ 11 вы можете использовать any_of. Например, если это vector<string> v; то:

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

Вот функция, которая будет работать на любой контейнер:

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 - это dependent name.

+1

Обратите внимание, что это иногда немного шире - например, оно будет работать для std :: set, но при этом дает ужасную производительность по сравнению с функцией-членом find(). Я нашел, что лучше всего добавить специализацию для контейнеров с более быстрым поиском (set/map, unordered_ *) –

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!"); 
    } 
} 
+3

Я бы не рекомендовал злоупотреблять перегрузкой оператора таким образом. – Leon

+1

Леон, я согласен с тобой, семантически это неправильно. Я использую его, чтобы сделать модульные тесты более четкими. –

3

С повышением вы можете использовать any_of_equal:

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

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