web-dev-qa-db-fra.com

Comment vérifier qu'un élément est dans un std :: set?

Comment vérifiez-vous qu'un élément est dans un ensemble?

Existe-t-il un équivalent plus simple du code suivant:

myset.find(x) != myset.end()
286
fulmicoton

La manière typique de vérifier l'existence dans de nombreux conteneurs STL est la suivante:

const bool is_in = container.find(element) != container.end();
350
unwind

Une autre façon de simplement dire si un élément existe est de vérifier la count()

if (myset.count(x)) {
   // x is in the set, count is 1
} else {
   // count zero, i.e. x not in the set
}

Cependant, la plupart du temps, il me faut un accès à l'élément où que je vérifie son existence.

Il faudrait donc que je trouve l'itérateur de toute façon. Ensuite, bien sûr, il est préférable de simplement le comparer à end aussi.

set< X >::iterator it = myset.find(x);
if (it != myset.end()) {
   // do something with *it
}

C++ 2

En C++ 20, l'ensemble obtient une fonction contains, de sorte que ce qui suit devient possible

if (myset.contains(x)) {
  // x is in the set
} else {
  // no x 
}
177
Pieter

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 vous ouvrirait la voie à l'écriture de code peu efficace. Une telle méthode ferait probablement juste une this->find(key) != this->end() en interne, mais considérons ce que vous faites quand la clé est bien présente; dans la plupart des cas, vous voudrez alors obtenir l'élément et faire quelque chose avec. Cela signifie que vous devrez faire une seconde find(), ce qui est inefficace. Il vaut mieux utiliser directement find pour pouvoir mettre en cache votre résultat, comme suit:

Container::const_iterator it = myContainer.find(key);
if (it != myContainer.end())
{
  // Do something with it, no more lookup needed.
}
else
{
  // Key was not present.
}

Bien sûr, si vous ne vous souciez pas de l'efficacité, vous pouvez toujours rouler vous-même, mais dans ce cas, vous ne devriez probablement pas utiliser le C++ ...;)

36
Tim

Si vous deviez ajouter une fonction contains, elle pourrait ressembler à ceci:

#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();
}

Cela fonctionne avec std::set, d'autres conteneurs STL et même des tableaux de longueur fixe:

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));
}

Modifier:

Comme indiqué dans les commentaires, j’ai involontairement utilisé une fonction nouvelle pour C++ 0x (std::begin et std::end). Voici l'implémentation presque triviale de 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);
    }

}
6
Sam Harwell

Vous pouvez également vérifier si un élément est dans le jeu ou non lors de son insertion. La version à élément unique renvoie une paire, avec sa paire de membres :: first définie sur un itérateur pointant sur l'élément nouvellement inséré ou sur l'élément équivalent déjà présent dans l'ensemble. La paire :: second élément de la paire est définie sur true si un nouvel élément a été inséré ou sur false si un élément équivalent existait déjà.

Par exemple: Supposons que l'ensemble contienne déjà 20 en tant qu'élément.

 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.

Si l'élément est nouvellement inséré, pair :: first indiquera la position du nouvel élément dans le jeu.

4
Prashant Shubham

Dans C++ 2 nous aurons enfin la méthode 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";
    }
}
4
Denis Sablukov

Écrivez votre propre:

template<class T>
bool checkElementIsInSet(const T& elem, const std::set<T>& container)
{
  return container.find(elem) != container.end();
}
2
stefaanv

J'utilise

if(!my_set.count(that_element)) //Element is present...
;

Mais ce n’est pas aussi efficace que

if(my_set.find(that_element)!=my_set.end()) ....;

Ma version me fait gagner du temps en écrivant le code. Je le préfère de cette façon pour un codage compétitif.

2
Manas Bondale

// Syntaxe générale

       set<int>::iterator ii = find(set1.begin(),set1.end(),"element to be searched");

/ * dans le code ci-dessous, j'essaie de trouver l'élément 4 dans et int défini s'il est présent ou non * /

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.
 }
0
sanjeev

J'ai pu écrire une fonction générale contains pour std::list et 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

Cela nettoie un peu la syntaxe.

Mais je ne pouvais pas utiliser template template magic pour que cela fonctionne arbitrairement dans des conteneurs 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() ;
}

Tout commentaire sur l'amélioration de la dernière réponse serait gentil.

0
bobobobo