यह कैसे जांचें कि एक तत्व एक std :: set में है?


329

आप कैसे जांचते हैं कि एक तत्व एक सेट में है?

क्या निम्नलिखित कोड के बराबर सरल है:

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

4
उससे सरल तरीका प्राप्त करने का एकमात्र तरीका एक बूलियन विधेय होगा: टेम्पलेट <टाइपनेम टी> बूल सदस्य (टी कांस्टेबल और आइटम)। और यह आपके द्वारा पूछे जा रहे लाइन के संदर्भ में (कवर के तहत) लागू किया जाएगा।
डॉन वेकफील्ड 16

जवाबों:


399

विशिष्ट तरीका जैसे कई एसटीएल कंटेनरों में होने की जाँच करने के लिए std::map, std::set... है:

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

25
यह सेट और नक्शे के लिए विशिष्ट है। वैक्टर, सूचियाँ आदि में कोई सदस्य कार्य नहीं है।
विल्हेमटेल 13

8
IMO काउंट () का उपयोग करना बेहतर होता है क्योंकि यह केवल छोटा होता है और यह पियर द्वारा उत्तर में उल्लिखित बूल में परिवर्तित होता है। मुझे समझ नहीं आ रहा है कि यह उत्तर क्यों स्वीकार किया गया और इतने सारे अंक ...
ОгШен бобајић

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) {...}में आकर्षण है कि इसे सिर्फ एक ही पेड़ देखने की आवश्यकता है ...
एकॉनगुआ

23
वहाँ है set.contains(x)कि C ++ 20 मानक में एक बूल देता है। मुझे नहीं पता कि इसे पाने के लिए हमें 2020 तक क्यों ले जाया गया है।
gremwell

215

एक तत्व मौजूद है या नहीं, यह बताने का दूसरा तरीका है count()

if (myset.count(x)) {
   // x is in the set, count is 1
} else {
   // count zero, i.e. x not in the set
}

हालांकि, अधिकांश समय, मैं खुद को उस तत्व तक पहुंच की आवश्यकता महसूस करता हूं जहां मैं इसके अस्तित्व की जांच करता हूं।

तो मैं वैसे भी itter खोजने के लिए होगा। फिर, निश्चित रूप से, इसकी तुलना करना endबहुत बेहतर है।

set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
   // do something with *it
}

सी ++ 20

C ++ 20 सेट में एक 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
@ फ़्रीच के लिए यह प्रासंगिक है multisetऔर multimapमैंने सोचा था? हालाँकि अभी भी यह बताना अच्छा है :)
पीटर

83
std :: सेट आमतौर पर एक ऑर्डर किए गए ट्री स्ट्रक्चर के साथ लागू किया जाता है, इसलिए गणना करें () और ढूंढें () दोनों में O (logn) होगा। न तो सेट में सभी तत्वों पर पुनरावृति होगी।
एलन

14
@FrerichRaabe - क्या आप निश्चित हैं? चूंकि यह केवल setएक सदस्य के लिए ही संभव है , जो मेल खाता हो, तो क्या फंक्शन को इस तरह से लागू नहीं किया जाएगा, जैसे कि पहले तत्व का पता लगाने के बाद रुकना है, इस मामले में, जैसा कि पीटर बताते हैं? किसी भी मामले में उपयोगी उत्तर!
दान निसानबाम

14
@DanNissenbaum हाँ, आप बिलकुल सही हैं (और इसलिए + पीटर और + एलन हैं): std :: set के लिए, दो कार्य प्रदर्शन के मामले में बराबर हैं। इसलिए भले ही मेरी टिप्पणी का पहला भाग ( count()कभी भी तेजी से नहीं हो find()) अभी भी, दूसरा भाग वास्तव में लागू नहीं है std::set। हालाँकि, मुझे लगता है कि इसके पक्ष में एक और तर्क दिया जा सकता है find(): यह अधिक अभिव्यंजक है, यानी इस बात पर जोर दिया जाता है कि आप एक तत्व को खोजने की कोशिश कर रहे हैं, जो संख्याओं की संख्या गिनने के बजाय है।
फ्राइरिच राबे

42

बस स्पष्ट करने के लिए, 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 ++ का उपयोग नहीं करना चाहिए ...);


44
सेट के बारे में क्या? आमतौर पर आपके पास पहले से ही तत्व है, लेकिन अगर यह अंदर है, तो बस जांचना चाहते हैं।
एलाजार लीबोविच

8
क्या आपके पास इसका कोई संदर्भ है कि क्या यह वास्तविक कारण है कि इस तरह की विधि / कार्य को stl में शामिल नहीं किया गया है, या यह केवल आपके शिक्षित अनुमान है?
Fabio A.

3
@FabioA। यह मेरा शिक्षित अनुमान है।
टिम

1
@Adhemar, स्थिरता बिल्कुल एसटीएल के मजबूत पक्ष नहीं है ... ( list::remove, remove(makes_sense_only_for_vector, iterators)...)
Elazar Leibovich

3
मुझे इससे कोई मतलब नहीं है कि इसमें कोई फीचर शामिल नहीं है क्योंकि कोई इसका गलत इस्तेमाल कर सकता है अगर उन्हें नहीं पता होता कि वे क्या कर रहे हैं। प्रोग्रामिंग उन लोगों के लिए है जो अपने लिए सोच सकते हैं और अपने कोड और इसके प्रदर्शन के लिए जिम्मेदार हैं
slawekwin

13

में सी ++ 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::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);
    }

}

1
@ Adhemar, यह वास्तव में अक्षम था , लेकिन आपके द्वारा बताए गए कारण के लिए बिल्कुल भी नहीं।
सैम हरवेल

@Paul: सुनिश्चित करें कि आप के लिए विशेषज्ञता शामिल है std::set, और याद रखें कि यह केवल उचित है अगर केवल एक चीज जिसे आपको जानना आवश्यक है वह है अस्तित्व।
सैम हैरवेल

@ 280Z28: std :: start (कंटेनर)? एसटीएल मानक क्या है? यह मेरे gcc पर संकलन नहीं करता है।
स्टेफानव

@stefannv: हे, यह C ++ 0x के लिए नया है। मैंने ऊपर अपने कंपाइलर से कार्यान्वयन जोड़ा।
सैम हरवेल

2
@ Adhemar: यदि आप जानते हैं कि सेट में एक मान है, तो आपके पास पहले से ही मूल्य है। एकमात्र कारण जिसे आपको पुनरावृत्ति की आवश्यकता होगी, वह तत्व को सेट से मिटाना है। यदि आप सभी को यह जानना है कि संग्रह में कोई मूल्य है या नहीं, तो यह समाधान किसी भी अन्य समाधान से कम कुशल नहीं है।
सैम हरवेल

4

आप यह भी देख सकते हैं कि तत्व डालने के दौरान कोई तत्व सेट में है या नहीं। एकल तत्व संस्करण एक जोड़ी लौटाता है, जिसके सदस्य जोड़े के साथ :: पहले सेट करने के लिए या तो नए सम्मिलित तत्व या सेट में पहले से ही समतुल्य तत्व की ओर इशारा करते हुए। यदि कोई नया तत्व सम्मिलित किया गया था या यदि पहले से ही समतुल्य तत्व मौजूद था, तो जोड़ी :: जोड़ी में दूसरा तत्व सत्य पर सेट है।

उदाहरण के लिए: मान लीजिए कि सेट में पहले से ही एक तत्व के रूप में 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.

यदि तत्व जोड़ी की तुलना में नया डाला जाता है :: पहले सेट में नए तत्व की स्थिति को इंगित करेगा।


2

खुद लिखिए:

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

4
बस इतना किया: टेम्पलेट <class T> स्थिर इनलाइन बूल में (const std :: set <T> & S, T x) {return (S.find (x)! = S.end ()); }
फुलिमोटोन 14

4
@ अंपुल स्थिर वैश्विक कार्य नहीं बनाते हैं। इसके बजाय अपने कार्य को एक अनाम नामस्थान में रखें: यह उन कार्यों को बनाने का C ++ तरीका है जो अन्य संकलन इकाइयों में लिंक नहीं करेंगे। इसके अलावा, आपका टी पैरामीटर एक कॉन्स्टेक्ट रेफरेंस होना चाहिए, कॉन्स्टीट्यूशन के लिए और दक्षता के लिए।
विल्हेमटेल

-1: एसटीएल शैली में बिल्कुल नहीं और नहीं । यदि आप एसटीएल का उपयोग नहीं कर रहे हैं तो यह ठीक है, लेकिन यदि आप एसटीएल का उपयोग कर रहे हैं तो आपको कम से कम इसके मानकों का पालन करने का प्रयास करना चाहिए।
सैम हरवेल

1
@ 280Z28: मुझे खेद है कि मेरा कोड आपके मानकों पर नहीं है, मैं सिर्फ यह दिखा रहा था कि यदि आपको एसटीएल का इंटरफ़ेस पसंद नहीं है, तो आप अपना स्वयं का लिख ​​सकते हैं। जी, टेम्पर्ड नहीं? कैसे अस्थायी हो जाता है? आपका उदाहरण ठीक है, इसका मतलब यह नहीं है कि मेरा बुरा है। यह ओपी द्वारा पूछे गए सेट पर अधिक केंद्रित है।
स्टेफानव

1
@ 280Z28: मैं सिर्फ एक बिंदु बना रहा था। मैंने सोचा था कि लोग चित्र प्राप्त करने के लिए पर्याप्त बुद्धिमान होंगे।
स्टेफानव 19

2

मैं उपयोग करता हूं

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

लेकिन यह उतना कुशल नहीं है

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

मेरा संस्करण केवल कोड लिखने में अपना समय बचाता है। मैं इसे प्रतिस्पर्धी कोडिंग के लिए इस तरह से पसंद करता हूं।


हाँ, count()। कोई भी यह समझने में असमर्थ है कि बूलियन अभिव्यक्ति में उपयोग किया जाने वाला पूर्णांक-लौटाने वाला फ़ंक्शन गैर-शून्य के लिए परीक्षण कर रहा है, सी / सी ++ मुहावरों के महान समुद्र में कई, कई अन्य निशान हैं। और, जैसा कि ऊपर उल्लेख किया गया है, वास्तव में सेट के लिए उतना ही कुशल होना चाहिए, जो सवाल था।
रॉन बुर्क

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 :: वेक्टर को अतिरिक्त आबंटक की आवश्यकता है क्योंकि टेम्पलेट तर्क और std :: सेट को एक आबंटक और एक कम टेम्पलेट तर्क की आवश्यकता है। ये लाइनें woulkd काम करती हैं: टेम्प्लेट <टेम्पलेट <क्लास, क्लास> क्लास STLContainer, क्लास T, क्लास A> बूल होता है (STLContainer <T, A> कंटेनर, T elt) {return find (container.begin) (, कंटेनर) ), एलटी); = कंटेनर.एंड (); } टेम्पलेट <टेम्पलेट <क्लास, क्लास, क्लास> क्लास STLContainer, क्लास T, क्लास L, क्लास A> बूल होता है (STLContainer <T, A, L> कंटेनर, T elt) {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.
 }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.