J'essayais d'effacer une gamme d'éléments de la carte en fonction de conditions particulières. Comment le faire en utilisant les algorithmes STL?
Au départ j'ai pensé à utiliser remove_if
mais ce n'est pas possible car remove_if ne fonctionne pas pour les conteneurs associatifs.
Existe-t-il un algorithme équivalent "remove_if" qui fonctionne pour la carte?
En guise d'option simple, j'ai pensé à parcourir la carte et à effacer. Mais est-ce que faire une boucle sur la carte et effacer une option sûre? (Car les itérateurs deviennent invalides après l'effacement)
J'ai utilisé l'exemple suivant:
bool predicate(const std::pair<int,std::string>& x)
{
return x.first > 2;
}
int main(void)
{
std::map<int, std::string> aMap;
aMap[2] = "two";
aMap[3] = "three";
aMap[4] = "four";
aMap[5] = "five";
aMap[6] = "six";
// does not work, an error
// std::remove_if(aMap.begin(), aMap.end(), predicate);
std::map<int, std::string>::iterator iter = aMap.begin();
std::map<int, std::string>::iterator endIter = aMap.end();
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
return 0;
}
for(auto iter=aMap.begin(); iter!=aMap.end(); ){ ....}
pour réduire l'encombrement. Le repos est comme d'autres l'ont dit. Cette question m'a évité de me fendre les cheveux pour le moment ;-)Réponses:
Presque.
Ce que vous aviez à l'origine incrémenterait l'itérateur deux fois si vous en supprimiez un élément; vous pourriez potentiellement ignorer les éléments qui devaient être effacés.
C'est un algorithme courant que j'ai vu utilisé et documenté dans de nombreux endroits.
[EDIT] Vous avez raison de dire que les itérateurs sont invalidés après un effacement, mais seuls les itérateurs référençant l'élément qui est effacé, les autres itérateurs sont toujours valides. D'où l'utilisation
iter++
dans l'erase()
appel.la source
map
, renvoient l'itérateur suivant à partir deerase(iter)
. C'est beaucoup plus propre à faireiter = erase( iter )
.erase_if pour std :: map (et autres conteneurs)
J'utilise le modèle suivant pour cette chose même.
Cela ne retournera rien, mais supprimera les éléments de std :: map.
Exemple d'utilisation:
Deuxième exemple (vous permet de passer une valeur de test):
la source
std
. Je comprends pourquoi il n'est pas membre destd::map
, mais je pense que quelque chose comme ça devrait être dans la bibliothèque standard.std::map
et autres.Maintenant,
std::experimental::erase_if
est disponible dans l'en-tête<experimental/map>
.Voir: http://en.cppreference.com/w/cpp/experimental/map/erase_if
la source
J'ai obtenu cette documentation de l' excellente référence SGI STL :
Ainsi, l'itérateur que vous avez qui pointe vers l'élément à effacer sera bien sûr invalidé. Faites quelque chose comme ceci:
la source
erase
être appelé. Ils sont donc effectivement équivalents. Pourtant, je préfère fortement votre version à l'original.Le code d'origine n'a qu'un seul problème:
Ici, le
iter
est incrémenté une fois dans la boucle for et une autre fois en effacement, ce qui aboutira probablement à une boucle infinie.la source
Voici une solution élégante.
la source
D'après les notes de fond de:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
un conteneur associatif de paire ne peut pas fournir d'itérateurs mutables (tels que définis dans les exigences de Trivial Iterator), car le type de valeur d'un itérateur mutable doit être Assignable, et la paire n'est pas Assignable. Cependant, un conteneur associatif de paire peut fournir des itérateurs qui ne sont pas complètement constants: des itérateurs tels que l'expression (* i) .second = d est valide.
la source
Première
Deuxièmement, le code suivant est bon
Lors de l'appel d'une fonction, les paramètres sont évalués avant l'appel de cette fonction.
Ainsi, quand iter ++ est évalué avant l'appel à effacer, l'opérateur ++ de l'itérateur retournera l'élément courant et pointera vers l'élément suivant après l'appel.
la source
IMHO il n'y a pas d'
remove_if()
équivalent.Vous ne pouvez pas réorganiser une carte. Vous ne pouvez
donc
remove_if()
pas mettre vos paires d'intérêt à la fin sur lesquelles vous pouvez appelererase()
.la source
Basé sur la réponse d'Iron Savior Pour ceux qui aimeraient fournir une gamme plus proche des itérateurs fonctionnels std.
Curieux de savoir s'il existe un moyen de perdre les
ContainerT
éléments et de les obtenir de l'itérateur.la source
Réponse de Steve Folly Je me sens le plus efficace.
Voici une autre solution simple mais moins efficace :
La solution utilise
remove_copy_if
pour copier les valeurs souhaitées dans un nouveau conteneur, puis échange le contenu du conteneur d'origine avec celui du nouveau:la source
Si vous souhaitez effacer tous les éléments dont la clé est supérieure à 2, le meilleur moyen est
Fonctionne uniquement pour les plages, pas pour aucun prédicat.
la source
J'utilise comme ça
la source