Comment vérifier qu'un élément est dans un std::set?
Comment voulez-vous vérifier qu'un élément est dans un jeu?
Est-il un simple équivalent au code suivant:
myset.find(x) != myset.end()
- La seule façon d'obtenir de plus simple que cela, ce serait un prédicat booléen: template <typename T> bool membre(T const &item). Et qui serait mis en œuvre (sous le capot) en termes de la ligne que vous parlez.
Vous devez vous connecter pour publier un commentaire.
Typique de la façon de vérifier l'existence dans de nombreux conteneurs STL est:
if (container.insert(foo).second == true) { //do something as this is the first time we've seen foo }
je l'ai changé pourif (container.find(foo) == container.end) { //do something as this is the first time we've seen foo container.insert(foo); }
L'examinateur n'a pas aimé mon changement, mais il semble de plus en plus évident pour moi que l'intention est.std::find(container.begin(), container.end(), element) != container.end()
; O(N) problème reste le même, bien sûr...if(container.find(foo) == container.end())
besoin de faire un arbre de recherche pour trouver l'élément premier - si pas trouvé, alors vous devez faire un deuxième arbre de recherche pour trouver le bon emplacement d'insertion. La variante originaleif(container.insert(foo).second) {...}
a le charme qu'il a juste besoin d'un seul arbre de recherche...set.contains(x)
qui renvoie un booléen en C++ 20 standard. Je ne sais pas pourquoi il nous a fallu jusqu'en 2020 pour le faire.Une autre façon de dire simplement si un élément existe, c'est pour vérifier la
count()
La plupart du temps, cependant, je me retrouve à avoir besoin d'accéder à l'élément où je l'ai vérifier son existence.
Si je dois trouver l'itérateur de toute façon. Alors, bien sûr, il est préférable de simplement comparer à
end
trop.C++ 20
En C++20 enregistre
contains
de la fonction, de sorte que celui-ci devient possiblecount()
au lieu defind()
n'est jamais mieux, mais potentiellement pire. C'est parce quefind()
sera de retour après le premier match,count()
toujours itérer sur tous les éléments.multiset
etmultimap
je pensais? Toujours bon à signaler cependant 🙂set
pour contenir un membre qui correspond à, ne serait pas la fonction d'être mis en œuvre de manière à s'arrêter après avoir trouvé le premier élément, dans ce cas, comme Pieter de points? Réponse utile en tout cas!count()
jamais être plus rapide quefind()
) tient toujours, la deuxième partie est en effet pas applicable àstd::set
. Cependant, je pense autre argument peut être fait en faveur defind()
: il est plus expressif, c'est à dire souligne que vous êtes essayer de trouver un élément, au lieu de compter le nombre de occurrances.find()
mêmecount()
a les mêmes performances et plus concis, parce que d'autres développeurs peuvent confondre la raison pour laquelle vous utilisezcount()
quand juste vérifier si il est dans le conteneur..count
pourset
utilisefind
:count(const key_type& __x) const { return _M_t.find(__x) == _M_t.end() ? 0 : 1; }
.find()
: Si le type de conteneur changer tout le code à l'aide decount()
besoin d'être fixé. Mais tous lesfind()
code fonctionnent encore correctement.count
? Peut un ensemble ont le même élément deux fois?has()
oucontains()
est beaucoup plus auto-documentation. Bonne chose qu'en C++, 20 🙂Juste pour préciser, la raison pourquoi il n'est pas membre comme
contains()
dans ces types de conteneurs est parce que vous vous ouvrir à l'écriture inefficace code. Une telle méthode serait probablement juste de faire unthis->find(key) != this->end()
en interne, mais réfléchissez à ce que vous faites lorsque la clé est bien présente; dans la plupart des cas, vous aurez alors voulez obtenir de l'élément et de faire quelque chose avec elle. Cela signifie que vous auriez à faire un deuxièmefind()
, ce qui est inefficace. Il est préférable d'utiliser les trouver directement, de sorte que vous pouvez mettre en cache le résultat, comme suit:Bien sûr, si vous n'avez pas à se soucier de l'efficacité, vous pouvez toujours passer votre propre, mais dans ce cas, vous probablement ne devrait pas être à l'aide de C++... 😉
list::remove
,remove(makes_sense_only_for_vector, iterators)
...)std::remove
algorithme fonctionne avec n'importe quel STL-comme conteneur, mais ne pas supprimer physiquement les éléments (car elle ne connaît pas la structure interne du conteneur, c'est à dire unstd::list
est différent d'unstd::vector
). C'est pourquoi le membreerase
(erase_after
pourforward_list
) est utilisé en conjonction avecstd::remove
. Conteneurs associatifs définir leurs propres versions de certains algorithmes (commeremove
,find
etc) pour des raisons d'efficacité: c'est à dire, dans unlist
, vous venez de rétablir le lien avec les pointeurs internes, sans effectuer le générique de l'algorithme de suppression.list
ouslist
. Quel serait le résultat? Est-ce que jamais souhaitable?remove
membre. La cohérence n'est pas le côté fort de la STL...std::remove
surlist
œuvres, il fait ce qu'il fait sur unstd::vector
, déplace leend
itérateur de coeur. Avez-vous un exemple de comportement étrange?std::remove(a_list.begin(), a_list.end())
utile? Que faut-il réellement faire de la liste chaînée?std::remove
pour les deuxstd::vector
etstd::list
, et à mon avis, il se comporte de manière identique dans les deux cas, ideone.com/Psbepycontains()
. En effet, il ya beaucoup de raisons que vous pourriez vouloir pour voir si quelque chose est dans un jeu sans l'obtention d'un itérateur pour elle. En fait, avec l'ensemble, vous ne pouvez pas faire beaucoup avec qui itérateur autre que supprimer de l'élément, dont vous pouvez déjà faire sans l'accord préalable de recherche de toute façon.Si vous allez à ajouter un
contains
fonction, il pourrait ressembler à ceci:Cela fonctionne avec
std::set
, d'autres conteneurs STL, et même des tableaux de longueur fixe:Edit:
Comme l'a souligné dans les commentaires, j'ai involontairement utilisé une fonction nouvelle pour C++0x (
std::begin
etstd::end
). Ici est la quasi-trivial de mise en œuvre de VS2010:std::set
, et n'oubliez pas que c'est seulement approprié si le que chose que vous devez savoir, c'est l'existence.std::begin(container)
àcontainer.begin()
(même pour la fin), ou 2) d'inclure les nouvelles fonctions de l'utilitaire à la base.Vous pouvez aussi vérifier si un élément est dans le jeu ou pas lors de l'insertion de l'élément.
Le seul élément de la version de retourner une paire, avec ses membres de la paire::première série à un itérateur pointant vers le nouvellement inséré l'élément ou de l'élément équivalent déjà dans le jeu. La paire::deuxième élément de la paire est définie sur true si un élément nouveau a été inséré ou false si un élément équivalent existait déjà.
Par exemple: Supposons que l'ensemble a déjà 20 comme un élément.
Si l'élément est inséré de paire: d'abord en va point à la position de l'élément nouveau dans la série.
Dans C++20 nous allons enfin obtenir
std::set::contains
méthode.Écrire votre propre:
- Je utiliser
Mais il n'est pas aussi efficace que
Ma version seulement d'économiser de mon temps dans l'écriture du code. Je préfère cette façon concurrentielle pour le codage.
count()
. Quelqu'un incapable de saisir un entier-de retour de la fonction utilisée dans une expression Booléenne est un test pour les non-zéro va avoir beaucoup, beaucoup d'autres travaux dans la grande mer de C/C++ idiomes. Et, comme l'a noté ci-dessus, doit être vraiment aussi efficace pour les jeux, c'était la question.J'étais capable d'écrire un général
contains
fonction pourstd::list
etstd::vector
,Cela nettoie la syntaxe un peu.
Mais je ne pouvais pas utiliser modèle de paramètre de modèle de la magie pour faire ce travail arbitraire des conteneurs stl.
Des commentaires au sujet de l'amélioration de la dernière réponse, ce serait bien.
template<typename CONTAINER, typename CONTAINEE> bool contains(const CONTAINER& container, const CONTAINEE& needle) { return find(container.begin(), container.end(), needle) != container.end();
//Syntaxe générale
/* dans le code ci-dessous je suis en train d'essayer de trouver l'élément 4 et int set s'il est présent ou pas*/