요소가 std :: set에 있는지 확인하는 방법?


329

요소가 세트에 있는지 어떻게 확인합니까?

다음 코드와 같은 간단한 것이 있습니까?

myset.find(x) != myset.end()

4
그것보다 간단하게 만드는 유일한 방법은 부울 술어입니다 : template <typename T> bool member (T const & item). 그리고 그것은 당신이 요구하는 라인의 관점에서 (표지 아래) 구현 될 것입니다.
Don Wakefield

답변:


399

일반적인 방법으로는 다음과 같은 많은 STL 컨테이너에 존재를 확인하기 위해 std::map, std::set...입니다 :

const bool is_in = container.find(element) != container.end();

25
이것은 세트와 맵에만 해당됩니다. 벡터,리스트 등에는 멤버 찾기 기능이 없습니다.
wilhelmtell 2009

8
count ()를 사용하는 IMO는 단순히 더 짧고 Pieter의 답변에 명시된 것처럼 bool로 변환하기 때문에 더 좋습니다. 나는이 답변이 왜 받아 들여 졌는지 이해하지 못합니다.
Огњен Шобајић

4
완전성을 위해 벡터 / 목록은 std :: find : std::find(container.begin(), container.end(), element) != container.end(); 물론 O (N) 문제가 남아 있습니다.
Aconcagua

10
@MichaelMathews 변형 : if(container.find(foo) == container.end())요소를 먼저 찾으려면 트리 조회를 수행해야합니다. 찾을 수없는 경우 올바른 삽입 위치를 찾으려면 두 번째 트리 조회를 수행해야합니다. 원래 변형 if(container.insert(foo).second) {...}에는 하나의 단일 트리 조회 만 필요하다는 매력이 있습니다 ...
Aconcagua

23
set.contains(x)그 반환 C ++ 20 표준 부울. 2020 년까지 왜 우리를 데려
갔는지 모르겠습니다

215

요소가 존재하는지 간단히 알려주는 또 다른 방법은 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
}

C ++ 20

C ++ 20에서 set은 contains함수를 얻으므로 https://stackoverflow.com/a/54197839/895245

if (myset.contains(x)) {
  // x is in the set
} else {
  // no x 
}

102
count()대신에 사용 하는 find()것이 더 좋지는 않지만 잠재적으로 더 나쁩니다. find()첫 번째 일치 후에 반환 되기 때문에 count()항상 모든 요소를 ​​반복 하기 때문 입니다 .
Frerich Raabe가

34
만 관련이 @Frerich multisetmultimap내가 생각? 그래도 지적하는 것이 좋습니다 :)
Pieter

83
std :: set은 일반적으로 순서가 지정된 트리 구조로 구현되므로 count () 및 find () 모두 O (logn)을 갖습니다. 세트의 모든 요소를 ​​반복하지는 않습니다.
Alan

14
@FrerichRaabe-확실합니까? set일치하는 멤버를 하나만 포함 할 수 있기 때문에 Pieter가 지적한 것처럼 첫 번째 요소를 찾은 후 중지하는 방식으로 함수를 구현하지 않습니까? 어떤 경우에도 유용한 답변!
Dan Nissenbaum

14
@DanNissenbaum 예, 당신이 옳습니다 (+ Peter 및 + Alan도 마찬가지입니다). std :: set의 경우 두 기능은 성능면에서 동일합니다. 따라서 내 의견의 첫 번째 부분 ( count()보다 빠르지 않음 find())이 여전히 유지되지만 두 번째 부분은 실제로 적용되지 않습니다 std::set. 그러나 나는 또 다른 주장이 유리 할 수 ​​있다고 생각합니다 find(). 더 표현력이 뛰어납니다. 즉, 발생 횟수를 세는 대신 요소를 찾으려고 강조합니다.
Frerich Raabe

42

분명히 말하면, contains()이러한 컨테이너 유형 과 같은 멤버가없는 이유는 비효율적 인 코드를 작성할 수 있기 때문입니다. 이러한 방법은 아마도 this->find(key) != this->end()내부적으로 수행 할 것이지만 실제로 키가있을 때 수행하는 작업을 고려하십시오. 대부분의 경우 요소를 가져 와서 무언가를 원할 것입니다. 이것은 당신이 두 번째를해야한다는 것을 의미하며 find(), 이는 비효율적입니다. find를 직접 사용하는 것이 좋으므로 다음과 같이 결과를 캐시 할 수 있습니다.

auto it = myContainer.find(key);
if (it != myContainer.end())
{
    // Do something with it, no more lookup needed.
}
else
{
    // Key was not present.
}

물론 효율성에 신경 쓰지 않는다면 항상 자신 만 롤링 할 수는 있지만 아마도 C ++을 사용해서는 안됩니다 ...;)


44
세트는 어떻습니까? 일반적으로 이미 요소가 있지만 그 요소가 있는지 확인하려고합니다.
Elazar Leibovich

8
이것이 그러한 방법 / 기능이 stl에 포함되어 있지 않은 실제 이유인지 또는 교육받은 추측인지에 대한 언급이 있습니까?
Fabio A.

3
@FabioA. 내 교육받은 추측이야.
Tim

1
@Adhemar, 일관성은 STL의 강력한면이 아닙니다 ... ( list::remove, remove(makes_sense_only_for_vector, iterators)...)
Elazar Leibovich

3
누군가 자신이 무엇을하고 있는지 알지 못하는 경우 기능을 잘못 사용할 수 있으므로 기능을 포함하지 않는 것은 의미가 없습니다. 프로그래밍은 스스로 생각하고 코드와 성능에 책임이있는 사람들을위한 것입니다.
slawekwin

13

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

6

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::beginstd::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);
    }

}

1
@Adhemar, 실제로 이었다 하지만 당신이 언급 한 이유로 모두에서 비효율적.
Sam Harwell

@ 폴은 : 당신이에 대한 전문성을 포함 있는지 확인 std::set하고 경우에만 적절한 것 기억 에만 당신이 알아야 할 것은 존재입니다.
Sam Harwell

@ 280Z28 : std :: begin (컨테이너)? 그게 무슨 STL 표준입니까? 내 gcc에서 컴파일되지 않습니다.
stefaanv 2009

@ stefannv : heh, C ++ 0x의 새로운 기능입니다. 위의 컴파일러에서 구현을 추가했습니다.
Sam Harwell

2
@Adhemar : 집합에 값이 포함되어 있으면 이미 값을 알고있는 것입니다. 반복자가 필요한 유일한 이유는 세트에서 요소를 지우는 것입니다. 경우 모두 당신이 필요로하는이 컬렉션 값이 포함되어 있는지 여부를 알 수있다,이 솔루션은 덜 효율적으로 다른 솔루션에 비해입니다.
Sam Harwell

4

요소를 삽입하는 동안 요소가 설정되어 있는지 여부를 확인할 수도 있습니다. 단일 요소 버전은 멤버 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보다 새로 삽입 된 경우 set에서 새 요소의 위치를 ​​가리 킵니다.


2

직접 작성하십시오 :

template<class T>
bool checkElementIsInSet(const T& elem, const std::set<T>& container)
{
  return container.find(elem) != container.end();
}

4
방금 그렇게 : template <class T> 정적 인라인 부울 contains (const std :: set <T> & S, T x) {return (S.find (x)! = S.end ()); }
fulmicoton 2009

4
@paul은 정적 전역 함수를 만들지 않습니다. 대신 익명 네임 스페이스에 함수를 넣으십시오. 다른 컴파일 단위에 연결되지 않는 함수를 만드는 C ++ 방식입니다. 또한 T 매개 변수는 const-correctness 및 효율성을위한 const 참조 여야합니다.
wilhelmtell 2009

-1 : 템플릿 수 없음이 아니라 모두에서 STL 스타일입니다. STL을 사용하지 않는 경우에는 문제가 없지만 STL을 사용하는 경우 최소한 해당 표준을 따라야합니다.
Sam Harwell

1
@ 280Z28 : 내 코드가 표준에 맞지 않아 죄송합니다. STL 인터페이스가 마음에 들지 않으면 직접 작성할 수 있음을 보여주었습니다. 템플릿이 아닌 Jeez? 템플릿을 어떻게 작성해야합니까? 귀하의 예는 괜찮아 보인다고해서 내 것이 나쁘다는 것을 의미하지는 않습니다. OP의 요청에 따라 세트에 더 집중되어 있습니다.
stefaanv 2009

1
@ 280Z28 : 난 그냥 지적했다. 나는 사람들이 사진을 찍기에 충분할 것이라고 생각했다.
stefaanv 2009

2

나는 사용한다

if(!my_set.count(that_element)) //Element is present...
;

그러나 그것은 효율적이지 않습니다

if(my_set.find(that_element)!=my_set.end()) ....;

내 버전은 코드 작성 시간 만 절약합니다. 나는 경쟁력있는 코딩을 위해이 방법을 선호합니다.


count(). 부울 식에 사용되는 정수 반환 함수가 0이 아닌 것을 테스트한다는 것을 알 수없는 사람은 C / C ++ 관용구의 바다에서 많은 다른 수고를 겪을 것입니다. 그리고 위에서 언급했듯이 실제로 세트에 대해 효율적이어야합니다. 이것이 문제였습니다.
Ron Burk

0

나는 일반적으로 쓸 수 있었다 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();
fulmicoton

std :: vector에는 템플릿 인수로 추가 할당자가 필요하고 std :: set에는 할당 자 및 적은 템플릿 인수가 필요하기 때문에 작동하지 않습니다. 이 줄은 작동합니다 : template <template <class, class> class STLContainer, class T, class A> bool contains (STLContainer <T, A> container, T elt) {return find (container.begin (), container.end ( ), elt)! = container.end (); } template <template <class, class, class> 클래스 STLContainer, 클래스 T, 클래스 L, 클래스 A> bool contains (STLContainer <T, A, L> 컨테이너, Telt) {return find (container.begin (), 컨테이너 .end (), elt)! = container.end (); }
tgmath

0

// 일반 구문

       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.
 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.