Comment vérifiez-vous qu'un élément est dans un ensemble?
Y a-t-il un équivalent plus simple du code suivant:
myset.find(x) != myset.end()
Comment vérifiez-vous qu'un élément est dans un ensemble?
Y a-t-il un équivalent plus simple du code suivant:
myset.find(x) != myset.end()
C'est spécifique pour les ensembles et les cartes. les vecteurs, listes, etc. n'ont pas de fonction membre find.
@wilhelmtell Oui, vous avez raison. Parce que chercher un élément dans un vecteur ou une liste est inefficace en O(N), il n'y a pas de fonction membre find() implémentée dans un vecteur ou une liste.
J'utilise IMO count() est meilleur car il est simplement plus court et il se convertit en bool comme indiqué dans la réponse de Pieter. Je ne comprends pas pourquoi cette réponse a été acceptée et a reçu autant de points...
Une autre façon de simplement vérifier si un élément existe est de vérifier le count()
if (myset.count(x)) {
// x est dans l'ensemble, le compte est de 1
} else {
// compte nul, c'est-à-dire x n'est pas dans l'ensemble
}
La plupart du temps, cependant, je me retrouve à avoir besoin d'accéder à l'élément partout où je vérifie son existence.
Donc je devrais trouver l'itérateur de toute façon. Ensuite, bien sûr, il vaut mieux simplement le comparer à end
aussi.
set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
// faire quelque chose avec *it
}
C++ 20
En C++20, set obtient une fonction contains
, donc ce qui suit devient possible comme mentionné à : https://stackoverflow.com/a/54197839/895245
if (myset.contains(x)) {
// x est dans l'ensemble
} else {
// pas de x
}
Notez que l'utilisation de count()
au lieu de find()
n'est jamais meilleure mais potentiellement pire. Cela est dû au fait que find()
renverra après le premier match, count()
itérera toujours sur tous les éléments.
@Frerich ce n'est pertinent que pour les multiset
et les multimap
je pensais? Toujours bon de le souligner :)
Est généralement implémenté avec une structure d'arbre ordonné, donc count () et find () auront tous les deux O (log n). Aucun ne parcourra tous les éléments de l'ensemble.
Juste pour clarifier, la raison pour laquelle il n'y a pas de membre comme contains()
dans ces types de conteneurs est parce que cela ouvrirait la porte à l'écriture de code inefficace. Une telle méthode ferait probablement simplement un this->find(key) != this->end()
en interne, mais réfléchissez à ce que vous faites lorsque la clé est effectivement présente ; dans la plupart des cas, vous voudrez alors obtenir l'élément et faire quelque chose avec. Cela signifie que vous devriez faire un second find()
, ce qui est inefficace. Il vaut mieux utiliser directement find
, afin de pouvoir mettre en cache votre résultat, de la manière suivante :
auto it = myContainer.find(key);
if (it != myContainer.end())
{
// Faire quelque chose avec, plus besoin de recherche.
}
else
{
// La clé n'était pas présente.
}
Évidemment, si vous ne vous souciez pas de l'efficacité, vous pouvez toujours créer votre propre méthode, mais dans ce cas, vous ne devriez probablement pas utiliser C++... ;)
Que dire des ensembles? En général, vous avez déjà l'élément, mais vous voulez juste vérifier s'il est présent.
Avez-vous des références indiquant si c'est effectivement la raison pour laquelle une méthode/fonction n'est pas incluse dans la STL, ou est-ce simplement votre hypothèse éclairée?
Si vous deviez ajouter une fonction contains
, elle pourrait ressembler à ceci :
#include
#include
template inline
bool contains(TInputIterator first, TInputIterator last, const T& value)
{
return std::find(first, last, value) != last;
}
template inline
bool contains(const TContainer& container, const T& value)
{
// Cela fonctionne avec plus de conteneurs mais nécessite std::begin et std::end
// de C++0x, que vous pouvez obtenir de deux manières :
// 1. En utilisant un compilateur C++0x ou
// 2. En incluant les fonctions utilitaires ci-dessous.
return contains(std::begin(container), std::end(container), value);
// Cela fonctionne avant C++0x (et sans les fonctions utilitaires ci-dessous, mais ne fonctionne pas
// pour les tableaux de longueur fixe.
//return contains(container.begin(), container.end(), value);
}
template inline
bool contains(const std::set& container, const T& value)
{
return container.find(value) != container.end();
}
Ceci fonctionne avec std::set
, d'autres conteneurs STL, et même des tableaux de longueur fixe :
void test()
{
std::set set;
set.insert(1);
set.insert(4);
assert(!contains(set, 3));
int set2[] = { 1, 2, 3 };
assert(contains(set2, 3));
}
Comme indiqué dans les commentaires, j'ai utilisé involontairement une fonction nouvelle à C++0x (std::begin
et std::end
). Voici l'implémentation presque triviale de VS2010 :
namespace std {
template inline
typename _Container::iterator begin(_Container& _Cont)
{ // obtenir le début de la séquence
return (_Cont.begin());
}
template inline
typename _Container::const_iterator begin(const _Container& _Cont)
{ // obtenir le début de la séquence
return (_Cont.begin());
}
template inline
typename _Container::iterator end(_Container& _Cont)
{ // obtenir la fin de la séquence
return (_Cont.end());
}
template inline
typename _Container::const_iterator end(const _Container& _Cont)
{ // obtenir la fin de la séquence
return (_Cont.end());
}
template inline
_Ty *begin(_Ty (&_Array)[_Size])
{ // obtenir le début du tableau
return (&_Array[0]);
}
template inline
_Ty *end(_Ty (&_Array)[_Size])
{ // obtenir la fin du tableau
return (&_Array[0] + _Size);
}
}
@Adhemar, c'était en fait inefficace, mais pas du tout pour la raison que vous avez mentionnée.
@Paul: Assurez-vous d'inclure la spécialisation pour std::set
, et n'oubliez pas que c'est uniquement approprié si la seule chose que vous devez savoir est son existence.
@280Z28: std::begin(container)? Quelle norme STL est-ce ? Cela ne se compile pas sur mon gcc.
Juste faites le : modèle statique en ligne contient(const std::set& S, T x) { retourner (S.find(x) != S.end()); }
@paul ne créez pas de fonctions globales statiques. Placez plutôt votre fonction dans un espace de noms anonyme : c'est la manière de créer des fonctions en C++ qui ne se lieront pas à d'autres unités de compilation. De plus, votre paramètre T devrait être une référence constante, pour la correction constante et pour l'efficacité.
-1: Pas modelé et pas du tout au style STL. C'est correct si vous n'utilisez pas STL, mais si vous l'utilisez, vous devriez au moins essayer de suivre ses normes.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
5 votes
La seule façon de simplifier davantage serait un prédicat booléen : template bool membre(T const &élément). Et cela serait implémenté (sous-jacent) en termes de la ligne sur laquelle vous posez des questions.