2010-12-07 40 views
2

quand je supprime d'un conteneur non imbriqué comme un vecteur, je suis en train de faire quelque chose comme:Effacer l'idiome pour supprimer dans un conteneur imbriqué? (Suppression de ceux externes, la STL C de)

struct is_to_remove 
{ 
    is_to_remove(dynamic_bitset<>& x) : x(x) {} 
    const bool operator()(unsigned int id) 
    { 
     return x[id]; 
    } 

private: 
    dynamic_bitset<> x; 
}; 

inline static void remove_elements_in_vector(vector<unsigned int>& vec, boost::dynamic_bitset<>& to_remove) 
{ 
    // use the erase-remove idiom to remove all elements marked in bitset 
    vec.erase(remove_if(vec.begin(), vec.end(), is_to_remove(to_remove)), vec.end()); 
} 

C'est le soi-disant erase-remove idiom.

Maintenant, i ont des secondes données strucure vector<vector<unsigned int> >deque<vector<unsigned int> > ou, où i souhaite supprimer les éléments de récipient externe (qui est lui-même un récipient du type interne) selon l'une bitset.

  • Est-il possible d'utiliser l'idiome d'effacement supprimer sur ce type de conteneurs imbriqués?
  • Si oui, comment est-ce possible?
  • Existe-t-il des restrictions? (comme: vec de vec est possible, mais pas deque de vec)?

Ma première approche naïve était la suivante. J'ai supposé que remove_if est l'itération séquentielle et dans l'ordre sur les éléments et de décider les uns après les autres. Est-ce une mauvaise hypothèse?

struct is_to_remove_new 
{ 
    is_to_remove_new(dynamic_bitset<>& x, unsigned int index) : x(x), index(index) {} 
    const bool operator()(vector<unsigned int> & vec) 
    { 
     return x[index++]; 
    } 

private: 
    dynamic_bitset<> x; 
    unsigned int index; 
}; 

inline static void remove_elements_in_vectorvector(vector<vector<unsigned int> >& vec, boost::dynamic_bitset<>& to_remove) 
{ 
    // use the erase-remove idiom to remove all elements marked in bitset 
    vec.erase(remove_if(vec.begin(), vec.end(), is_to_remove_new(to_remove, 0)), vec.end()); 
} 

Le résultat est mauvais, donc je suis à la recherche d'une solution correcte ici. Je suppose que j'ai assumé certaines choses qui ne sont pas garanties. Pour moi, la question de base est la suivante: Comment obtenir l'identité du conteneur interne pour vérifier s'il doit être retiré..
Mon approche naïve affichée ci-dessus compte juste et suppose un traitement séquentiel.

Merci pour votre aide.

Sascha

mise à jour et d'alerte

Pour un vecteur vecteurs o, solution Stas travaille beaucoup. Mais je pense que cette solution ne fonctionnera pas pour une deque de vecteurs car une deque n'est pas sauvegardée de manière contiguë. Cela signifie que le calcul de l'index dans le foncteur échoue.

Quelqu'un peut-il vérifier cela?

Répondre

3

Peu importe quels éléments sont dans le vecteur. Si vous définissez lequel d'entre eux doit être supprimé, ils seront supprimés.

Comme vous l'avez dit, la question est de savoir comment identifier un élément dans un vecteur. La réponse la plus évidente est par son index [0; vector_size - 1].

Grâce à un vecteur, vous pouvez facilement obtenir un index d'élément, par l'élément lui-même.

std::vector<std::string> vec; 
vec.push_back("zero"); 
vec.push_back("one"); 
vec.push_back("two"); 

std::string& elem = vec[2]; 
int index = std::distance(&vec[0], &elem); // get element index by element itself 
// index == 2 

Ainsi, vous pouvez facilement identifier les éléments vectoriels par les indices à l'intérieur remove_if prédicat algorithme. Jetez un oeil à l'exemple suivant.Il est assez stupide et utiliser codés en dur std::bitset<6>, mais cela est juste une illustration:

#include <vector> 
#include <string> 
#include <bitset> 

struct ToRemove 
{ 
    ToRemove(std::vector<std::string>& vec, const std::string& mask) 
    : m_vec(vec) 
    , m_mask(mask) 
    {} 

    bool operator()(std::string& obj) 
    { 
     const int index = std::distance(&m_vec[0], &obj); 
     return m_mask[index]; 
    } 

    std::vector<std::string>& m_vec; 
    std::bitset<6> m_mask; 
}; 

Utilisation

int main (int argc, char const *argv[]) 
{ 
    std::vector<std::string> vec; 
    vec.push_back("zero"); 
    vec.push_back("one"); 
    vec.push_back("two"); 
    vec.push_back("three"); 
    vec.push_back("four"); 
    vec.push_back("five"); 

    std::string mask = ("010011"); // Remove "zero", "one" and "four" 
    vec.erase(remove_if(vec.begin(), vec.end(), ToRemove(vec, mask)), vec.end()); 

    for (unsigned i = 0; i < vec.size(); ++i) 
    { 
     std::cout << vec[i] << " "; 
    } 
    std::cout << std::endl; 

    return 0; 
} 

Résultat

two three five 
+0

fonctionne comme un charme. Je vous remercie. Prochaine chose à essayer: faites ceci avec un vecteur :-). – sascha

+0

Après plus de tests, je pense que cette solution fonctionne pour un vecteur externe (où les garanties contiguës sont en attente), mais pas pour une deque externe. Anybode peut-il vérifier cela? Je pense en raison de la nature non contiguë d'une deque, l'index calculé dans le foncteur est faux -> erreur. – sascha