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

440

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

if ( item_present )
   do_this();
else
   do_that();
  • 1
    поиск в векторе очень медленный, так как вы должны смотреть на каждый элемент вектора, поэтому подумайте об использовании карты, если вы делаете много поисков
  • 6
    @naumcho: если вектор отсортирован, всегда есть бинарный поиск, как показано ниже. Это делает его таким же быстрым, как карта, и если вы храните только значения (а не карты ключ / значение), тогда он будет использовать намного меньше памяти.
Показать ещё 3 комментария
Теги:
vector
std

16 ответов

693
Лучший ответ

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

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

Возвращает bool (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), будет ли это "быстрее в теории"?
  • 9
    Возможно. Это зависит от того, как часто вы будете искать пустые векторы.
Показать ещё 22 комментария
86

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

  • 3
    Хороший ответ! Найти всегда о (п). lower_bound равен o (log (n)), если используется с итераторами с произвольным доступом.
  • 25
    Сортировка - это O (nlogn), поэтому она стоит только если вы выполняете больше, чем O (logn) поиск.
Показать ещё 2 комментария
38

Используйте find из заголовка алгоритма stl.I показало его использование с типом 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 () также может быть подходящим. Это позволяет искать, используя произвольный предикат вместо равенства.
  • 0
    К сожалению, ваш комментарий слишком поздно. Ответ, который я дал, также упоминает find_if.
26

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

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

#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 из контейнера для типа элемента. Я добавил ответ как этот.
9

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

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

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

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

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

5

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

if (any_of(v.begin(), v.end(), bind2nd(equal_to<string>(), item)))
   do_this();
else
   do_that();
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()
}
4

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

template <class Container> 
const bool Contains(Container& container, const typename Container::value_type& element) 
{
    return std::find(container.begin(), container.end(), element) != container.end();
}

Обратите внимание, что вы можете уйти с одним параметром шаблона, потому что вы можете извлечь value_type из Контейнера. Вам нужно typename, потому что Container::value_type является зависимым именем .

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

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

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

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

Другой пример с использованием операторов С++.

#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
    Я бы не советовал злоупотреблять перегрузкой операторов таким способом.
  • 2
    Леон, я согласен с тобой, семантически это не правильно. Я использую его, чтобы сделать модульные тесты более четкими.
2

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

int t=count(vec.begin(),vec.end(),item);
  • 8
    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));
1

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

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню