Bir öğenin kümede olup olmadığını nasıl kontrol edersiniz?
Aşağıdaki kodun daha basit bir eşdeğeri var mı:
myset.find(x) != myset.end()
Bir öğenin kümede olup olmadığını nasıl kontrol edersiniz?
Aşağıdaki kodun daha basit bir eşdeğeri var mı:
myset.find(x) != myset.end()
Yanıtlar:
Tipik bir yol gibi birçok STL kaplarda varlığını denetlemek için std::map
, std::set
... geçerli:
const bool is_in = container.find(element) != container.end();
std::find(container.begin(), container.end(), element) != container.end()
:; O (N) problemi elbette var ...
if(container.find(foo) == container.end())
önce öğeyi bulmak için bir ağaç araması yapmanız gerekir - bulunmazsa, doğru ekleme konumunu bulmak için ikinci bir ağaç araması yapmanız gerekir. Orijinal varyant if(container.insert(foo).second) {...}
, sadece bir tek ağaç aramasına ihtiyaç duyduğu cazibeye sahiptir ...
set.contains(x)
bu döner C ++ 20 standardında Boole. Bunu almak için neden 2020'ye kadar götürdüğümü bilmiyorum.
Bir öğenin var olup olmadığını söylemenin başka bir yolu, count()
if (myset.count(x)) {
// x is in the set, count is 1
} else {
// count zero, i.e. x not in the set
}
Ancak çoğu zaman kendimi varlığını kontrol ettiğim her yerde öğeye erişmeye ihtiyaç duyuyorum.
Bu yüzden yineleyiciyi bulmak zorundayım. Sonra, elbette, bunu da basitçe karşılaştırmak daha iyidir end
.
set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
// do something with *it
}
C ++ 20
C ++ 20 setinde bir contains
fonksiyon elde edilir, bu nedenle aşağıdaki gibi mümkün olur: https://stackoverflow.com/a/54197839/895245
if (myset.contains(x)) {
// x is in the set
} else {
// no x
}
count()
Bunun yerine kullanmanın find()
asla daha iyi değil, potansiyel olarak daha kötü olduğunu unutmayın. Bunun nedeni find()
, ilk maçtan sonra geri dönecek, count()
her zaman tüm unsurları tekrarlayacaktır.
multiset
ve multimap
düşündüm? Yine de işaret etmek iyi :)
set
eşleşen bir üye içermesi mümkün olduğundan, işlev ilk öğeyi bulduktan sonra, bu durumda Pieter'in belirttiği gibi durdurulacak şekilde uygulanamaz mı? Her durumda faydalı cevap!
count()
asla daha hızlı olmamakla birlikte find()
) hala geçerli olsa da, ikinci kısmı gerçekten geçerli değildir std::set
. Bununla birlikte, sanırım başka bir argüman lehine yapılabilir find()
: daha etkileyici, yani olay sayısını saymak yerine bir öğe bulmaya çalıştığınızı vurgular.
Açıklığa kavuşturmak gerekirse contains()
, bu kapsayıcı türlerinde olduğu gibi üye bulunmamasının nedeni, verimsiz kod yazmaya açmanızdır. Böyle bir yöntem muhtemelen sadece this->find(key) != this->end()
dahili olarak yapardı , ancak anahtar gerçekten mevcut olduğunda ne yaptığınızı düşünün; çoğu durumda öğeyi almak ve onunla bir şeyler yapmak istersiniz. Bu, bir saniye yapmanız gerektiği anlamına gelir find()
, bu da verimsizdir. Doğrudan bulmayı kullanmak daha iyidir, böylece sonucunuzu önbelleğe alabilirsiniz, böylece:
auto it = myContainer.find(key);
if (it != myContainer.end())
{
// Do something with it, no more lookup needed.
}
else
{
// Key was not present.
}
Tabii ki, verimliliği umursamıyorsanız, her zaman kendi başınıza dönebilirsiniz, ancak bu durumda muhtemelen C ++ kullanmamalısınız ...;)
list::remove
, remove(makes_sense_only_for_vector, iterators)
...)
In 20 C ++ nihayet alırsınız std::set::contains
yöntemi.
#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";
}
}
Bir contains
işlev ekleyecekseniz , şöyle görünebilir:
#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();
}
Bu std::set
, diğer STL kapları ve hatta sabit uzunluklu dizilerle çalışır:
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));
}
Yorumlarda belirtildiği gibi, yanlışlıkla C ++ 0x ( std::begin
ve std::end
) için yeni bir işlev kullandım . İşte VS2010'dan neredeyse önemsiz bir uygulama:
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
ve bunun yalnızca bilmeniz gereken tek şey varoluşsa uygun olduğunu unutmayın .
Ayrıca, öğeyi eklerken bir öğenin ayarlanıp ayarlanmadığını da kontrol edebilirsiniz. Tek elemanlı sürüm, üye çifti :: ilk olarak yeni eklenen öğeye veya zaten kümede bulunan eşdeğer öğeye işaret eden bir yineleyiciye ayarlanmış bir çift döndürür. Yeni bir öğe eklenmişse çiftteki pair :: second öğesi true değerine veya eşdeğer bir öğe zaten varsa false değerine ayarlanır.
Örneğin: Setin zaten öğe olarak 20'si olduğunu varsayalım.
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.
Eleman pair :: 'den daha yeni eklenirse, ilk önce kümedeki yeni elemanın konumunu gösterecektir.
Kendin yaz:
template<class T>
bool checkElementIsInSet(const T& elem, const std::set<T>& container)
{
return container.find(elem) != container.end();
}
kullanırım
if(!my_set.count(that_element)) //Element is present...
;
Ama bu kadar etkili değil
if(my_set.find(that_element)!=my_set.end()) ....;
Sürümüm yalnızca kod yazarken zaman kazanıyor. Rekabetçi kodlama için bu şekilde tercih ederim.
count()
,. Boole ifadesinde kullanılan bir tamsayı döndürme işlevinin sıfır olmayanları sınadığını kavrayamayan herkes, C / C ++ deyimlerinin büyük denizinde çok sayıda başka travmaya sahip olacaktır. Ve, yukarıda belirtildiği gibi, gerçekten setler için etkili olmalı, ki soru buydu.
İçin genel bir contains
işlev yazabildim std::list
ve 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
Bu sözdizimini biraz temizler.
Ama bu şablon keyfi stl kapları yapmak için şablon şablonu parametre büyü kullanamadı .
// 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() ;
}
Son cevabı geliştirmeyle ilgili herhangi bir yorum iyi olurdu.
template<typename CONTAINER, typename CONTAINEE> bool contains(const CONTAINER& container, const CONTAINEE& needle) { return find(container.begin(), container.end(), needle) != container.end();
// genel Sözdizimi
set<int>::iterator ii = find(set1.begin(),set1.end(),"element to be searched");
/ * aşağıdaki kodda varsa ve değilse 4 set ve int set eleman bulmaya çalışıyorum * /
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.
}