Как узнать, присутствует ли элемент в std :: vector?

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

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

person Joan Venge    schedule 20.02.2009    source источник
comment
поиск в векторе очень медленный, так как вам нужно смотреть на каждый отдельный элемент вектора, поэтому подумайте об использовании карты, если вы выполняете много поисков   -  person naumcho    schedule 21.02.2009
comment
@naumcho: Если вектор отсортирован, всегда есть бинарный поиск, как указано ниже. Это делает его таким же быстрым, как карта, и если вы храните только значения (а не карты ключ / значение), тогда он будет использовать намного меньше памяти.   -  person Adam Hawes    schedule 21.02.2009
comment
карты, конечно, не лучший выбор, но использование набора может быть полезным. Если вам нужно время поиска O (1), вам подойдет hash_set.   -  person Philipp    schedule 08.10.2010
comment
Превосходный ответ на повторяющийся вопрос: stackoverflow.com/a/3451045/472647   -  person CodeMouse92    schedule 18.06.2015
comment
Если вы собираетесь искать разные числа несколько раз, хеш-таблица будет более эффективной.   -  person NL628    schedule 25.11.2017


Ответы (17)


Вы можете использовать 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()

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

#include <algorithm>
#include <vector>

if ( std::find(vec.begin(), vec.end(), item) != vec.end() )
   do_this();
else
   do_that();
person MSN    schedule 20.02.2009
comment
Использование вместо этого std :: count (std :: count (...) ›0), будет ли это быстрее в теории? - person Klaim; 21.02.2009
comment
Возможно. Это зависит от того, как часто вы ищите пустые векторы. - person MSN; 21.02.2009
comment
Я не понимаю, как count () может быть быстрее, чем find (), поскольку find () останавливается, как только будет найден один элемент, а count () всегда должен сканировать всю последовательность. - person Éric Malenfant; 21.02.2009
comment
На самом деле вы хотите использовать! Vector.empty (). Но как бы там ни было. - person MSN; 22.02.2009
comment
Не забудьте #include <algorithm>, иначе вы можете получить очень странные ошибки, такие как «не удается найти соответствующую функцию в пространстве имен std». - person rustyx; 02.03.2012
comment
а bool. Это падение замены (или инициализации) item_present в исходном вопросе. - person MSN; 19.10.2012
comment
Никого не беспокоило, что, несмотря на то, что STL является объектно-ориентированным, .find() по-прежнему не функция-член std::vector, как вы ожидали? Интересно, не является ли это каким-то следствием использования шаблонов? - person bobobobo; 07.12.2012
comment
@bobobobo: ООП не имеет ничего общего с участниками или нечленами. И есть широко распространенная школа мысли, что если что-то не обязательно должно быть членом или когда это не дает никаких преимуществ при реализации в качестве члена, то это не должно быть членом; std::vector<>::find() не даст никаких преимуществ, и в этом нет необходимости, поэтому нет, он не должен быть членом. См. Также en.wikipedia.org/wiki/Coupling_%28computer_programming%29 - person Sebastian Mach; 04.02.2013
comment
Я почти опубликовал вопрос о том, можно ли это оптимизировать, вызвав только vector.end() один раз, прежде чем осознал, что, во-первых, если меня действительно волнует скорость, мне вообще не следует использовать find() в векторе, а во-вторых, этот вызов vector.end() один раз вместо двух - вряд ли вообще какое-либо улучшение. - person ArtOfWarfare; 11.02.2013
comment
@ArtOfWarfare из-за расположения кеша отсортированный vector часто будет намного быстрее искать, чем map или set. - person Steve Lorimer; 05.04.2013
comment
@ArtOfWarfare В-третьих, вы можете обнаружить, что end() call is inlined by the compiler so there's no actual call` - это всего лишь необработанный указатель. - person Frerich Raabe; 10.12.2013
comment
@phresnel: если не дает никаких преимуществ сделать find () членом std :: vector, как вообще текущие функции-члены дают преимущество, будучи членами std :: vector из std :: map ?? - person ; 09.09.2014
comment
@Gasso: Никто не оценил здравомыслие текущих участников, являющихся участниками этой темы. Я только что представил, что согласно определенной школе мысли, find не следует добавлять в качестве члена в std::vector; Вопрос о том, имеют ли существующие члены смысл или нет, не обсуждался, и действительно, STL не очень хорошо спроектирован во многих аспектах, в основном из-за отсутствия опыта (и мой пост был ответом на bobobobo, который подразумевал, что участники являются частью концепции ООП, но их нет) - person Sebastian Mach; 11.09.2014
comment
@phresnel Я бы сказал, что когда он не дает никаких преимуществ при реализации в качестве члена, это ложно для этого случая. Преимущество - упрощенный и понятный интерфейс. Например: mvec.find(key) != mvec.cend() предпочтительнее std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend(). - person swalog; 29.04.2015
comment
@bobobobo Ссылаясь на раздел Контейнеры и алгоритмы в sgi.com/tech/stl/stl_introduction .html, начинающийся со слов: Следует обратить внимание на два важных момента, связанных с вызовом реверсирования. Я думаю, что это проливает некоторый свет на мышление разработчиков STL, хотя можно все еще задаться вопросом, насколько это мышление предшествовало идее использования абстрактных классов C ++ для определения интерфейсов, чтобы сделать связь между алгоритмами и контейнерами более очевидной. - person koan911; 07.05.2015
comment
@MSN Зачем нам нужен! = Vector.end () в конце для проверки элемента? Не находит (vector.begin (), vector.end (), item) сам по себе, чтобы найти элемент - person John Constantine; 26.11.2015
comment
@bobobobo: причина, по которой функция find () не является членом вектора, в том, что она неэффективна. Когда объект STL имеет член, это означает, что это полезный и эффективный метод; это предполагает, что вы должны его использовать. Поскольку find () не может быть эффективно реализован для вектора, он не является членом вектора, и предлагается использовать другой контейнер, если вам нужно использовать операции find (). Это не имеет ничего общего с тем, что STL «плохо спроектирован», как предлагается в других комментариях. - person Pascal Engeler; 14.01.2016
comment
@PascalEngeler: Я бы сказал, дело не столько в том, является ли операция эффективной или нет, сколько в том, позволяет ли прямой доступ к внутренней структуре данных более эффективную реализацию алгоритма, чем общий, использующий итераторы. - person MikeMB; 09.06.2016
comment
@Claudiu в C ++ вы можете использовать любой синтаксис, который вам нравится, просто берет страницу с самым уродливым кодом и voilà - person Ap31; 13.09.2016
comment
@ ap31: это правда, но когда я использую такой код в продакшене, люди кричат ​​на меня :( - person Claudiu; 13.09.2016
comment
Сообщение об ошибке от GCC / GXX из-за того, что забыли #include заголовок <algorithm> при использовании std::find, стало еще хуже: error: cannot bind non-const lvalue reference of type ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >&’ to an rvalue of type ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >’ - person Kai Petzke; 12.02.2019
comment
У меня есть тип данных std :: vector ‹std :: any›. как использовать std :: find для вектора любого типа? - person Arun; 08.03.2019
comment
@bobobobo Столько разных парадигм программирования повсюду усложняет работу новичков. - person tf3; 20.02.2020
comment
@swalog std :: find не требует, чтобы пользователь просматривал весь диапазон. Итак, чтобы функция-член была равной, она должна быть: mvec.find(mvec.cbegin(), mvec.cend(), key) != mvec.cend(), что не является особенно чистым интерфейсом, чем функция, не являющаяся членом. - person James Mart; 29.06.2020
comment
@ Джеймс Март: это было давно, но сейчас я не понимаю, насколько это правда, подразумеваемое использование находит с одним аргументом типа элемента в качестве ключа, уже знает свой собственный диапазон и может остановитесь на первом матче, если таковой имеется. Другими словами, значения, которые вы предлагаете, должны быть переданы, уже известны в вызываемой области, поэтому вы можете отбросить их и сделать интерфейс более чистым. - person swalog; 29.06.2020
comment
@swalog Я просто говорю, что если вы сделаете интерфейс более чистым, ваша функция-член больше не будет напрямую имитировать std :: find. std find намеренно использует итераторы, чтобы позволить пользователю определить подмножество общего диапазона для поиска - person James Mart; 01.07.2020
comment
Справедливо. Однако речь шла о гипотетической перегрузке, которая неявно выполняет поиск по всему диапазону и как таковая не требует специфики диапазона. Если и всякий раз, когда кто-то хочет выполнить поиск в диапазоне (это не весь диапазон), вы должны использовать find или функцию-член, подобную той, что вы упомянули. - person swalog; 01.07.2020
comment
Это отстой. Должен быть метод std :: vector :: contains. - person Kiruahxh; 12.11.2020
comment
@SebastianMach Я так понимаю, что std::vector::find() не реализовано, так как не лучше std::find(). Проблема в том, что программист, который обновляет определенную структуру данных с std::vector до std::multiset (или std::set), затем должен пройти через код и обновить каждое место, где выполняется find(). Было бы неплохо, если бы API std::(multi)set и std::vector были как можно более похожими. - person Kai Petzke; 07.12.2020
comment
Это решение не работает для std::vector<std::shared_ptr...> и других выражений pimpl. Кто-нибудь знает как заставить работать ?? - person Richard McFriend Oluwamuyiwa; 10.04.2021
comment
Идея объектно-ориентированного программирования исходит от Хайдеггера и представляет собой концепцию того, как люди воспринимают мир и систематизируют информацию. Объектно-ориентированный дизайн - это структурирование кода таким образом, чтобы он был понятен людям. Таким образом, объекты-контейнеры (например, vector) должны имитировать концепцию контейнеров в реальном мире. Тот факт, что я должен сказать, какой тип объектов может содержать контейнер (параметр шаблона), не соответствует реальному миру, где контейнеры могут содержать все, что угодно, при условии, что там достаточно места. А поскольку поиск вещей в контейнерах - обычное дело, это должно быть частью интерфейса контейнера. - person bitjeep; 18.06.2021

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

person Brian Neal    schedule 20.02.2009
comment
Хороший ответ! Найти всегда o (n). lower_bound равно o (log (n)), если используется с итераторами произвольного доступа. - person Stephen Edmonds; 08.07.2009
comment
Сортировка выполняется за O (nlogn), поэтому она имеет смысл только в том случае, если вы выполняете больше, чем O (logn) поисков. - person liori; 15.06.2014
comment
@liori Верно, это зависит от ваших шаблонов использования. Если вам нужно отсортировать его только один раз, а затем неоднократно выполнять много поисков, это может вас спасти. - person Brian Neal; 17.06.2014
comment
@Brian Neal, сортировка большого вектора имеет смысл, если в нем должно быть много элементов для поиска. Сортировка будет O (nlogn), а O (n) будет лучше, если нужно найти элемент только один раз :) - person Swapnil B.; 11.03.2018
comment
Будьте осторожны, это может испортить ваше предсказание ветвления. - person Brice M. Dempsey; 18.08.2020

Используйте find из заголовка алгоритма stl. Я проиллюстрировал его использование с типом 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;
}
person m-sharp    schedule 20.02.2009
comment
В зависимости от потребностей OP, find_if () также может быть подходящим. Это позволяет искать, используя произвольный предикат вместо равенства. - person Éric Malenfant; 21.02.2009
comment
Упс, слишком поздно увидел твой комментарий. В ответе, который я дал, также упоминается find_if. - person Frank; 21.02.2009

Если ваш вектор не упорядочен, используйте подход, предложенный 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, чтобы сначала отсортировать вектор, чтобы гарантировать, что он упорядочен.

person spiralmoon    schedule 23.11.2012
comment
Вы не имеете в виду std::sort? qsort очень неэффективен для векторов .... см .: stackoverflow.com/questions/12308243/ - person Jason R. Mick; 16.08.2013
comment
Двоичный поиск будет работать лучше для больших контейнеров, но для маленьких контейнеров простой линейный поиск, вероятно, будет таким же быстрым или более быстрым. - person BillT; 31.03.2017

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

#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

... таким образом, он действительно четкий и читаемый. (Очевидно, вы можете повторно использовать шаблон в нескольких местах).

person Andy Krouwel    schedule 04.09.2013
comment
и вы можете заставить его работать для списков или векторов, используя 2 типа имен - person Erik Aronesty; 03.03.2015
comment
@ErikAronesty, вы можете обойтись одним аргументом шаблона, если вы используете value_type из контейнера для типа элемента. Я добавил такой ответ. - person Martin Broadhurst; 12.02.2016
comment
Вы в основном пишете: if true return true else return false. Метод может быть следующим: return std::find(Vec.begin(), Vec.end(), Element) != Vec.end(); - person Charles Gueunet; 08.10.2020

В 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();
person Deqing    schedule 11.08.2015
comment
bind1st и bind2nd устарели с C ++ 11 и полностью удалены в С ++ 17. Вместо этого используйте bind с placeholders и / или лямбдами. - person andreee; 30.04.2019

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

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 из контейнера. Вам нужен typename, потому что Container::value_type - это зависимое имя.

person Martin Broadhurst    schedule 11.02.2016
comment
Обратите внимание, что иногда это слишком широко - например, это сработает для std :: set, но даст ужасную производительность по сравнению с функцией-членом find (). Лучше всего добавить специализацию для контейнеров с более быстрым поиском (set / map, unordered_ *) - person Andy Krouwel; 02.11.2016
comment
Может быть, однажды они наконец добавят это в stdlib ... вместо того, чтобы людям снова и снова приходилось спрашивать, как заново изобрести такое крошечное колесо. Теперь это вполне жизнеспособно, когда в C ++ 20 есть ranges, так что его можно было бы просто назвать Range, а не Container, а Боб - ваш дядя. - person underscore_d; 01.07.2020

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

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

person David Thornley    schedule 20.02.2009
comment
Даже при поиске по значению вектор может быть хорошим выбором, если он отсортирован и вы используете binary_search, lower_bound или upper_bound. Если содержимое контейнера изменяется между поисками, вектор не очень хорош из-за необходимости повторной сортировки. - person Renze de Waal; 21.02.2009

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

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

person Frank    schedule 20.02.2009


Вы можете попробовать этот код:

#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()
}
person TrungTN    schedule 28.04.2012

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

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

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

person TankorSmash    schedule 15.06.2014

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

int t=count(vec.begin(),vec.end(),item);
person Aditya    schedule 11.03.2015
comment
find быстрее, чем count, потому что он не считает после первого совпадения. - person Camille Goudeseune; 16.08.2015

Если вы хотите найти строку в векторе:

    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));
person Gank    schedule 31.05.2013

(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

person Pavan Chandaka    schedule 26.03.2019

В последнее время я лично использовал шаблоны для работы с несколькими типами контейнеров одновременно, а не только с векторами. Я нашел аналогичный пример в Интернете (не помню, где), так что заслуга принадлежит тому, у кого я это украл. Этот конкретный шаблон, похоже, также обрабатывает необработанные массивы.

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);
}
person Pascal Laferrière    schedule 28.10.2019

person    schedule
comment
Зачем вам использовать указатель и рисковать, что пользователи передадут nullptr, который вы не обрабатываете? В этом просто нет необходимости. Кроме того, вы копируете T what, что может оказаться дорогостоящим и ненужным. Оба аргумента должны быть const ссылками, а не текущими. Наконец, я не знаю, зачем люди пишут if (condition) return true; else return false;, когда они могут просто писать return condition;. - person underscore_d; 01.07.2020
comment
Спасибо за предложение, в то время у меня не было такого опыта, и я тем временем переключился на Java :) Я обновил комментарий, дайте мне знать, лучше или есть еще что исправить. - person user3157855; 02.07.2020
comment
Теперь, когда вы получаете ссылки вместо указателей, вам нужно использовать . вместо ->. - person underscore_d; 03.07.2020