คุณจะตรวจสอบว่าองค์ประกอบอยู่ในชุดได้อย่างไร
มีรหัสต่อไปนี้ที่ง่ายกว่านี้หรือไม่:
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)
ที่คืนค่าบูลในมาตรฐาน C ++ 20 ฉันไม่รู้ว่าทำไมเราถึงต้องใช้เวลาจนถึงปี 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
}
C ++ 20
ในชุด C ++ 20 จะได้รับ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
และโปรดจำไว้ว่ามันเหมาะสมถ้าสิ่งเดียวที่คุณต้องรู้คือการมีอยู่
นอกจากนี้คุณยังสามารถตรวจสอบว่าองค์ประกอบอยู่ในชุดหรือไม่ในขณะที่แทรกองค์ประกอบ รุ่นองค์ประกอบเดียวส่งคืนคู่โดยมีสมาชิกเป็นคู่ :: ชุดแรกเป็นตัววนซ้ำชี้ไปที่องค์ประกอบที่เพิ่งแทรกใหม่หรือองค์ประกอบที่เทียบเท่าในชุด คู่ :: องค์ประกอบที่สองในคู่ตั้งเป็นจริงถ้าองค์ประกอบใหม่ถูกแทรกหรือเท็จถ้าองค์ประกอบเทียบเท่าอยู่แล้ว
ตัวอย่างเช่นสมมติว่าชุดนั้นมี 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.
หากองค์ประกอบถูกแทรกใหม่กว่าคู่ :: ก่อนจะชี้ไปที่ตำแหน่งขององค์ประกอบใหม่ในชุด
เขียนของคุณเอง:
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 in และ int set หากมีอยู่หรือไม่ * /
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.
}