Bagaimana Anda memeriksa bahwa suatu elemen ada di dalam suatu set?
Apakah ada persamaan yang lebih sederhana dari kode berikut:
myset.find(x) != myset.end()
Bagaimana Anda memeriksa bahwa suatu elemen ada di dalam suatu set?
Apakah ada persamaan yang lebih sederhana dari kode berikut:
myset.find(x) != myset.end()
Jawaban:
Cara khas untuk memeriksa keberadaan di banyak kontainer STL seperti std::map
, std::set
, ... adalah:
const bool is_in = container.find(element) != container.end();
std::find(container.begin(), container.end(), element) != container.end()
:; O (N) masalah tetap, tentu saja ...
if(container.find(foo) == container.end())
perlu melakukan pencarian pohon untuk menemukan elemen pertama - jika tidak ditemukan, maka Anda perlu melakukan pencarian pohon kedua untuk menemukan lokasi penyisipan yang benar. Varian asli if(container.insert(foo).second) {...}
memiliki pesona yang dibutuhkan hanya satu pencarian pohon tunggal ...
set.contains(x)
yang mengembalikan bool dalam standar C ++ 20. Saya tidak tahu mengapa kami sampai tahun 2020 untuk mendapatkannya.
Cara lain untuk mengatakan apakah suatu elemen ada adalah dengan memeriksa count()
if (myset.count(x)) {
// x is in the set, count is 1
} else {
// count zero, i.e. x not in the set
}
Namun, sebagian besar waktu, saya menemukan diri saya membutuhkan akses ke elemen di mana pun saya memeriksa keberadaannya.
Jadi saya harus menemukan iteratornya. Maka, tentu saja, lebih baik membandingkannya end
juga.
set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
// do something with *it
}
C ++ 20
Dalam set C ++ 20 mendapat contains
fungsi, jadi yang berikut menjadi mungkin seperti yang disebutkan di: https://stackoverflow.com/a/54197839/895245
if (myset.contains(x)) {
// x is in the set
} else {
// no x
}
count()
bukannya find()
tidak pernah lebih baik tetapi berpotensi lebih buruk. Ini karena find()
akan kembali setelah pertandingan pertama, count()
akan selalu beralih ke semua elemen.
multiset
dan multimap
saya pikir? Masih bagus untuk menunjukkan :)
set
mengandung satu anggota yang cocok, bukankah fungsi akan diimplementasikan sedemikian rupa untuk berhenti setelah menemukan elemen pertama, dalam hal ini, seperti yang ditunjukkan Pieter? Bagaimanapun, jawaban yang berguna!
count()
tidak pernah lebih cepat dari find()
) masih berlaku, bagian kedua memang tidak berlaku std::set
. Namun, saya kira argumen lain dapat dibuat dalam mendukung find()
: itu lebih ekspresif, yaitu menekankan bahwa Anda mencoba untuk menemukan elemen daripada menghitung jumlah kemunculan.
Hanya untuk memperjelas, alasan mengapa tidak ada anggota seperti contains()
dalam jenis wadah ini adalah karena itu akan membuka Anda untuk menulis kode yang tidak efisien. Metode seperti itu mungkin hanya akan melakukan this->find(key) != this->end()
internal, tetapi pertimbangkan apa yang Anda lakukan ketika kuncinya memang ada; dalam kebanyakan kasus, Anda akan ingin mendapatkan elemen dan melakukan sesuatu dengannya. Ini berarti Anda harus melakukan yang kedua find()
, yang tidak efisien. Lebih baik menggunakan find secara langsung, sehingga Anda dapat men-cache hasil Anda, seperti:
auto it = myContainer.find(key);
if (it != myContainer.end())
{
// Do something with it, no more lookup needed.
}
else
{
// Key was not present.
}
Tentu saja, jika Anda tidak peduli dengan efisiensi, Anda selalu dapat menggunakan roll Anda sendiri, tetapi dalam hal ini Anda mungkin tidak boleh menggunakan C ++ ...;)
list::remove
, remove(makes_sense_only_for_vector, iterators)
...)
Dalam C ++ 20 kita akhirnya akan mendapatkan std::set::contains
metode.
#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";
}
}
Jika Anda akan menambahkan contains
fungsi, mungkin terlihat seperti ini:
#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();
}
Ini bekerja dengan std::set
, wadah STL lainnya, dan bahkan susunan dengan panjang tetap:
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));
}
Seperti yang ditunjukkan dalam komentar, saya tidak sengaja menggunakan fungsi baru untuk C ++ 0x ( std::begin
dan std::end
). Berikut ini implementasi hampir sepele dari 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
, dan ingat bahwa itu hanya sesuai jika satu - satunya hal yang perlu Anda ketahui adalah keberadaan.
Anda juga dapat memeriksa apakah suatu elemen diatur atau tidak saat memasukkan elemen. Versi elemen tunggal mengembalikan pasangan, dengan pasangan anggotanya :: set pertama ke iterator yang menunjuk ke elemen yang baru saja dimasukkan atau ke elemen setara yang sudah ada di set. Elemen pasangan :: kedua dalam pasangan diatur ke true jika elemen baru dimasukkan atau salah jika elemen yang setara sudah ada.
Sebagai contoh: Misalkan set sudah memiliki 20 sebagai elemen.
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.
Jika elemen baru dimasukkan daripada pasangan :: pertama akan menunjuk ke posisi elemen baru di set.
Tulis milik Anda sendiri:
template<class T>
bool checkElementIsInSet(const T& elem, const std::set<T>& container)
{
return container.find(elem) != container.end();
}
saya menggunakan
if(!my_set.count(that_element)) //Element is present...
;
Tetapi itu tidak seefisien
if(my_set.find(that_element)!=my_set.end()) ....;
Versi saya hanya menghemat waktu saya dalam menulis kode. Saya lebih suka cara ini untuk pengkodean kompetitif.
count()
. Siapa pun yang tidak dapat memahami bahwa fungsi integer-return yang digunakan dalam ekspresi Boolean sedang menguji untuk non-nol akan memiliki banyak, banyak kerja keras lain di lautan besar idiom C / C ++. Dan, seperti disebutkan di atas, benar-benar harus seefisien untuk set, yang merupakan pertanyaan.
Saya dapat menulis contains
fungsi umum untuk std::list
dan 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
Ini sedikit membersihkan sintaks.
Tapi saya tidak bisa menggunakan templat parameter templat ajaib untuk membuat karya ini wadah stl sewenang-wenang.
// 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() ;
}
Setiap komentar tentang meningkatkan jawaban terakhir akan menyenangkan.
template<typename CONTAINER, typename CONTAINEE> bool contains(const CONTAINER& container, const CONTAINEE& needle) { return find(container.begin(), container.end(), needle) != container.end();
// Sintaksis umum
set<int>::iterator ii = find(set1.begin(),set1.end(),"element to be searched");
/ * dalam kode di bawah ini saya mencoba untuk menemukan elemen 4 di dan int ditetapkan apakah ada atau tidak * /
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.
}