Как вы проверяете, что элемент находится в наборе?
Есть ли более простой эквивалент следующего кода:
myset.find(x) != myset.end()
Как вы проверяете, что элемент находится в наборе?
Есть ли более простой эквивалент следующего кода:
myset.find(x) != myset.end()
Ответы:
Типичный способ проверить существование во многих STL контейнеров , таких как std::map, std::set... это:
const bool is_in = container.find(element) != container.end();
std::find(container.begin(), container.end(), element) != container.end():; O (N) проблема остается, конечно ...
if(container.find(foo) == container.end())нужно выполнить поиск по дереву, чтобы найти элемент - если он не найден, то нужно выполнить поиск по второму дереву, чтобы найти правильное место вставки. У оригинального варианта if(container.insert(foo).second) {...}есть очарование, что ему нужен только один поиск дерева ...
set.contains(x)что возвращает BOOL в ++ 20 стандарта C. Я не знаю, почему это заняло у нас до 2020 года.
Другой способ просто сказать, существует ли элемент, это проверить count()
if (myset.count(x)) {
// x is in the set, count is 1
} else {
// count zero, i.e. x not in the set
}
Однако в большинстве случаев мне нужен доступ к элементу, где бы я ни проверял его существование.
Так что я все равно должен найти итератор. Тогда, конечно, лучше просто сравнить с этим end.
set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
// do something with *it
}
С ++ 20
В C ++ 20 set получает containsфункцию, поэтому становится возможным следующее, как упомянуто по адресу: https://stackoverflow.com/a/54197839/895245
if (myset.contains(x)) {
// x is in the set
} else {
// no x
}
count()вместо find()никогда не лучше, но потенциально хуже. Это потому, find()что вернется после первого совпадения, count()всегда будет перебирать все элементы.
multisetи multimapя подумал? Тем не менее, приятно отметить, что :)
setсодержать только один совпадающий член, разве функция не будет реализована таким образом, чтобы останавливаться после нахождения первого элемента, в данном случае, как указывает Питер? Полезный ответ в любом случае!
count()никогда не быстрая, чем find()) по-прежнему имеет место, вторая часть действительно не применима к std::set. Тем не менее, я предполагаю, что можно привести еще один аргумент в пользу find(): он более выразителен, то есть подчеркивает, что вы пытаетесь найти элемент вместо подсчета количества вхождений.
Просто чтобы прояснить, причина, по которой contains()в этих типах контейнеров нет элементов, подобных тем, что это откроет вам возможность писать неэффективный код. Такой метод, вероятно, будет просто this->find(key) != this->end()внутренним, но подумайте, что вы делаете, когда ключ действительно присутствует; в большинстве случаев вы захотите получить элемент и что-то с ним сделать. Это означает, что вам нужно сделать секунду find(), что неэффективно. Лучше использовать поиск напрямую, чтобы вы могли кэшировать свой результат, например так:
auto it = myContainer.find(key);
if (it != myContainer.end())
{
// Do something with it, no more lookup needed.
}
else
{
// Key was not present.
}
Конечно, если вы не заботитесь об эффективности, вы всегда можете свернуть свои собственные, но в этом случае вам, вероятно, не следует использовать C ++ ...;)
list::remove, remove(makes_sense_only_for_vector, iterators)...)
В C ++ 20 мы наконец получим std::set::containsметод.
#include <iostream>
#include <string>
#include <set>
int main()
{
std::set<std::string> example = {"Do", "not", "panic", "!!!"};
if(example.contains("panic")) {
std::cout << "Found\n";
} else {
std::cout << "Not found\n";
}
}
Если вы собираетесь добавить containsфункцию, она может выглядеть так:
#include <algorithm>
#include <iterator>
template<class TInputIterator, class T> inline
bool contains(TInputIterator first, TInputIterator last, const T& value)
{
return std::find(first, last, value) != last;
}
template<class TContainer, class T> inline
bool contains(const TContainer& container, const T& value)
{
// This works with more containers but requires std::begin and std::end
// from C++0x, which you can get either:
// 1. By using a C++0x compiler or
// 2. Including the utility functions below.
return contains(std::begin(container), std::end(container), value);
// This works pre-C++0x (and without the utility functions below, but doesn't
// work for fixed-length arrays.
//return contains(container.begin(), container.end(), value);
}
template<class T> inline
bool contains(const std::set<T>& container, const T& value)
{
return container.find(value) != container.end();
}
Это работает с std::setдругими контейнерами STL и даже массивами фиксированной длины:
void test()
{
std::set<int> set;
set.insert(1);
set.insert(4);
assert(!contains(set, 3));
int set2[] = { 1, 2, 3 };
assert(contains(set2, 3));
}
Как указано в комментариях, я непреднамеренно использовал функцию, новую для C ++ 0x ( std::beginи std::end). Вот почти тривиальная реализация VS2010:
namespace std {
template<class _Container> inline
typename _Container::iterator begin(_Container& _Cont)
{ // get beginning of sequence
return (_Cont.begin());
}
template<class _Container> inline
typename _Container::const_iterator begin(const _Container& _Cont)
{ // get beginning of sequence
return (_Cont.begin());
}
template<class _Container> inline
typename _Container::iterator end(_Container& _Cont)
{ // get end of sequence
return (_Cont.end());
}
template<class _Container> inline
typename _Container::const_iterator end(const _Container& _Cont)
{ // get end of sequence
return (_Cont.end());
}
template<class _Ty,
size_t _Size> inline
_Ty *begin(_Ty (&_Array)[_Size])
{ // get beginning of array
return (&_Array[0]);
}
template<class _Ty,
size_t _Size> inline
_Ty *end(_Ty (&_Array)[_Size])
{ // get end of array
return (&_Array[0] + _Size);
}
}
std::set, и помните, что это уместно, только если единственное, что вам нужно знать, это существование.
Вы также можете проверить, находится ли элемент в наборе или нет при вставке элемента. Версия с одним элементом возвращает пару, в которой для ее элемента pair :: first установлено значение итератора, указывающее либо на вновь вставленный элемент, либо на эквивалентный элемент, уже находящийся в наборе. Элемент pair :: second в паре устанавливается равным true, если новый элемент был вставлен, или false, если эквивалентный элемент уже существует.
Например: предположим, что в наборе уже есть 20 в качестве элемента.
std::set<int> myset;
std::set<int>::iterator it;
std::pair<std::set<int>::iterator,bool> ret;
ret=myset.insert(20);
if(ret.second==false)
{
//do nothing
}
else
{
//do something
}
it=ret.first //points to element 20 already in set.
Если элемент недавно вставлен, то pair :: first будет указывать на позицию нового элемента в наборе.
Напишите свой собственный:
template<class T>
bool checkElementIsInSet(const T& elem, const std::set<T>& container)
{
return container.find(elem) != container.end();
}
я использую
if(!my_set.count(that_element)) //Element is present...
;
Но это не так эффективно, как
if(my_set.find(that_element)!=my_set.end()) ....;
Моя версия только экономит мое время при написании кода. Я предпочитаю это так для конкурентного кодирования.
count(). Любой, кто не в состоянии понять, что функция, возвращающая целое число, используемая в булевом выражении, проверяет ненулевое, будет иметь много, много других проблем в большом море идиом C / C ++. И, как отмечалось выше, действительно должно быть максимально эффективно для наборов, о чем и шла речь.
Я был в состоянии написать общую containsфункцию для std::listи std::vector,
template<typename T>
bool contains( const list<T>& container, const T& elt )
{
return find( container.begin(), container.end(), elt ) != container.end() ;
}
template<typename T>
bool contains( const vector<T>& container, const T& elt )
{
return find( container.begin(), container.end(), elt ) != container.end() ;
}
// use:
if( contains( yourList, itemInList ) ) // then do something
Это немного очищает синтаксис.
Но я не мог использовать магию параметра шаблона шаблона, чтобы заставить эту работу работать с произвольными stl-контейнерами.
// NOT WORKING:
template<template<class> class STLContainer, class T>
bool contains( STLContainer<T> container, T elt )
{
return find( container.begin(), container.end(), elt ) != container.end() ;
}
Любые комментарии об улучшении последнего ответа были бы хорошими.
template<typename CONTAINER, typename CONTAINEE> bool contains(const CONTAINER& container, const CONTAINEE& needle) { return find(container.begin(), container.end(), needle) != container.end();
// общий синтаксис
set<int>::iterator ii = find(set1.begin(),set1.end(),"element to be searched");
/ * в приведенном ниже коде я пытаюсь найти элемент 4 и установить int, если он присутствует или нет * /
set<int>::iterator ii = find(set1.begin(),set1.end(),4);
if(ii!=set1.end())
{
cout<<"element found";
set1.erase(ii);// in case you want to erase that element from set.
}