2010-07-28 4 views
2

J'ai un std::set et je dois effacer des éléments adjacents similaires:Iterate et effacer elments de std :: set

DnaSet::const_iterator next = dna_list.begin(); 
DnaSet::const_iterator actual = next; 
++next; 

while(next != dna_list.end()) // cycle over pairs, dna_list is the set 
{ 
    if (similar(*actual, *next)) 
    { 
     Dna dna_temp(*actual); // copy constructor 
     dna_list.erase(actual); // erase the old one 
     do 
     { 
      dna_temp.mutate(); // change dna_temp 
     } while(!dna_list.insert(dna_temp).second); // insert dna_temp 
    } 
    ++actual; 
    ++next; 
} 

Parfois, le programme ne peut pas sortir de la boucle principale. Je pense que le problème se produit lorsque j'efface le dernier élément du dna_list. Quelle est la bonne façon de faire cette tâche?

Répondre

5

Utilisez actual = next plutôt que ++actual.

Une fois que vous avez effacé actual, il s'agit d'un itérateur non valide, donc ++actual se comportera étrangement. next doit rester intact, donc l'affectation actual à next devrait fonctionner.

+0

oui, c'est le bug, merci –

2

Votre meilleure option est de créer un foncteur de comparaison qui utilise le prédicat similar(). Ensuite, tout ce que vous devez faire est de construire l'ensemble avec ce foncteur de comparaison et vous avez terminé. L'ensemble se verra deux éléments similaires comme identiques et ne laisser le premier à

struct lt_different { 
    bool operator()(int a, int b) { 
     return a < b && !similar(a, b); 
    } 

private: 
    bool similar(int a, int b) 
    { 
     // TODO:when are two elements similar? 
     const int EPSILON = 2; 
     return abs(a - b) < EPSILON; 
    } 
}; 

// ... 
set<int> o; // fill this set with your data 

// copy your data to a new set that rejects similar elements 
set<int,lt_different> s(o.begin(), o.end(), lt_different()); 

Vous pouvez travailler avec l'ensemble s: insérer des éléments, supprimer des éléments, modifier les éléments - et l'ensemble se fera en sorte. il n'y a pas deux éléments similaires dans l'ensemble. Cela dit, vous pouvez également écrire un algorithme vous-même, ne serait-ce que pour un choix alternatif. Jetez un oeil à std::adjacent_find() de <algorithm>. Il trouvera la première occurrence de deux éléments identiques consécutifs; Accrochez-vous à cette position. Avec cela trouvé, trouvez le premier élément de ce point qui est différent de ces éléments. Vous vous retrouvez avec deux itérateurs qui dénotent une gamme d'éléments similaires consécutifs. Vous pouvez utiliser la méthode erase() de l'ensemble pour les supprimer, car il y a une surcharge qui prend deux itérateurs. Mousser, rincer, répéter pour l'ensemble.

+0

Comment puis-je implémenter votre première idée? J'ai besoin d'implémenter 'operator ==' pour les éléments de l'ensemble? Je ne peux pas le faire, parce que le concept de similaire est différent du concept d'égalité, et j'ai besoin des deux. Peut-être existe-t-il un moyen de dire à 'std :: set' d'utiliser une fonction particulière (différente de' operator == ') pour décider si deux éléments sont des doublons? –

+0

J'ai mis à jour la réponse avec un exemple de code. Oui, tout ce qu'il faut c'est passer le constructeur de l'ensemble une fonction de comparaison de votre choix. – wilhelmtell

Questions connexes