Làm thế nào để bạn kiểm tra xem một phần tử có trong một tập hợp không?
Có tương đương đơn giản hơn của mã sau đây:
myset.find(x) != myset.end()
Làm thế nào để bạn kiểm tra xem một phần tử có trong một tập hợp không?
Có tương đương đơn giản hơn của mã sau đây:
myset.find(x) != myset.end()
Câu trả lời:
Cách thông thường để kiểm tra sự tồn tại trong nhiều container STL như std::map
, std::set
, ... là:
const bool is_in = container.find(element) != container.end();
std::find(container.begin(), container.end(), element) != container.end()
; Vấn đề O (N) vẫn còn, tất nhiên ...
if(container.find(foo) == container.end())
cần thực hiện tra cứu cây để tìm phần tử trước - nếu không tìm thấy, thì bạn cần thực hiện tra cứu cây thứ hai để tìm vị trí chèn chính xác. Biến thể ban đầu if(container.insert(foo).second) {...}
có sức hấp dẫn là nó chỉ cần một lần tra cứu cây ...
set.contains(x)
trả về một bool trong tiêu chuẩn C ++ 20. Tôi không biết tại sao chúng tôi phải mất đến năm 2020 để có được điều đó.
Một cách khác để chỉ đơn giản là nếu một phần tử tồn tại là kiểm tra count()
if (myset.count(x)) {
// x is in the set, count is 1
} else {
// count zero, i.e. x not in the set
}
Tuy nhiên, hầu hết thời gian, tôi thấy mình cần truy cập vào phần tử bất cứ nơi nào tôi kiểm tra sự tồn tại của nó.
Vì vậy, tôi phải tìm iterator nào. Sau đó, tất nhiên, tốt hơn là chỉ đơn giản so sánh nó với end
quá.
set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
// do something with *it
}
C ++ 20
Trong C ++ 20, bộ có một contains
chức năng, do đó, những điều sau đây có thể được đề cập tại: https://stackoverflow.com/a/54197839/895245
if (myset.contains(x)) {
// x is in the set
} else {
// no x
}
count()
thay vì find()
không bao giờ tốt hơn nhưng có khả năng tồi tệ hơn. Điều này là bởi vì find()
sẽ trở lại sau trận đấu đầu tiên, count()
sẽ luôn lặp đi lặp lại trên tất cả các yếu tố.
multiset
và multimap
tôi nghĩ sao? Vẫn tốt để chỉ ra mặc dù :)
set
chứa một thành viên phù hợp, nên chức năng sẽ không được thực hiện theo cách dừng lại sau khi định vị phần tử đầu tiên, trong trường hợp này, như Pieter chỉ ra? Câu trả lời hữu ích trong mọi trường hợp!
count()
không bao giờ nhanh hơn find()
) vẫn giữ, phần thứ hai thực sự không áp dụng được std::set
. Tuy nhiên, tôi đoán một lập luận khác có thể được đưa ra có lợi cho find()
: đó là biểu cảm hơn, tức là nhấn mạnh rằng bạn đang cố gắng tìm một yếu tố thay vì đếm số lần xuất hiện.
Chỉ cần làm rõ, lý do tại sao không có thành viên như contains()
trong các loại container này là bởi vì nó sẽ mở ra cho bạn để viết mã không hiệu quả. Một phương pháp như vậy có thể chỉ là thực hiện this->find(key) != this->end()
nội bộ, nhưng hãy xem xét những gì bạn làm khi chìa khóa thực sự có mặt; trong hầu hết các trường hợp, sau đó bạn sẽ muốn lấy phần tử và làm một cái gì đó với nó. Điều này có nghĩa là bạn phải làm một giây find()
, không hiệu quả. Tốt hơn là sử dụng find trực tiếp, vì vậy bạn có thể lưu trữ kết quả của mình, như vậy:
auto it = myContainer.find(key);
if (it != myContainer.end())
{
// Do something with it, no more lookup needed.
}
else
{
// Key was not present.
}
Tất nhiên, nếu bạn không quan tâm đến hiệu quả, bạn luôn có thể tự lăn, nhưng trong trường hợp đó có lẽ bạn không nên sử dụng C ++ ...;)
list::remove
, remove(makes_sense_only_for_vector, iterators)
...)
Trong C ++ 20 cuối cùng chúng ta cũng sẽ có được std::set::contains
phương thức.
#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";
}
}
Nếu bạn định thêm một contains
chức năng, nó có thể trông như thế này:
#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();
}
Điều này hoạt động với std::set
, các container STL khác và thậm chí các mảng có độ dài cố định:
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));
}
Như đã chỉ ra trong các bình luận, tôi đã vô tình sử dụng một chức năng mới cho C ++ 0x ( std::begin
và std::end
). Đây là cách triển khai gần như tầm thường từ 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
và nhớ rằng nó chỉ phù hợp nếu điều duy nhất bạn cần biết là sự tồn tại.
Bạn cũng có thể kiểm tra xem một phần tử có được thiết lập hay không trong khi chèn phần tử. Phiên bản phần tử đơn trả về một cặp, với cặp thành viên của nó :: đầu tiên được đặt thành một trình vòng lặp trỏ đến phần tử mới được chèn hoặc phần tử tương đương đã có trong tập hợp. Phần tử cặp :: thứ hai trong cặp được đặt thành đúng nếu phần tử mới được chèn hoặc sai nếu phần tử tương đương đã tồn tại.
Ví dụ: Giả sử tập hợp đã có 20 là một phần tử.
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.
Nếu phần tử mới được chèn hơn cặp :: đầu tiên sẽ trỏ đến vị trí của phần tử mới trong tập hợp.
Viết của riêng bạn:
template<class T>
bool checkElementIsInSet(const T& elem, const std::set<T>& container)
{
return container.find(elem) != container.end();
}
tôi sử dụng
if(!my_set.count(that_element)) //Element is present...
;
Nhưng nó không hiệu quả bằng
if(my_set.find(that_element)!=my_set.end()) ....;
Phiên bản của tôi chỉ tiết kiệm thời gian của tôi bằng cách viết mã. Tôi thích nó theo cách này để mã hóa cạnh tranh.
count()
. Bất kỳ ai cũng không thể hiểu rằng hàm trả về số nguyên được sử dụng trong biểu thức Boolean đang kiểm tra khác không sẽ có nhiều, nhiều chuyến đi khác trong biển thành ngữ C / C ++ tuyệt vời. Và, như đã lưu ý ở trên, thực sự nên có hiệu quả cho các bộ, đó là câu hỏi.
Tôi đã có thể viết một contains
hàm chung cho std::list
và 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
Điều này làm sạch cú pháp một chút.
Nhưng tôi không thể sử dụng ma thuật tham số mẫu để làm cho công việc này chứa các thùng chứa stl tùy ý.
// 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() ;
}
Bất kỳ ý kiến về việc cải thiện câu trả lời cuối cùng sẽ được tốt đẹp.
template<typename CONTAINER, typename CONTAINEE> bool contains(const CONTAINER& container, const CONTAINEE& needle) { return find(container.begin(), container.end(), needle) != container.end();
// Cú pháp chung
set<int>::iterator ii = find(set1.begin(),set1.end(),"element to be searched");
/ * trong đoạn mã dưới đây tôi đang cố gắng tìm phần tử 4 trong và int set nếu nó có mặt hay không * /
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.
}