[C++] STL : map et set
Résolu
Bonjour,
J'essaye de générer un fichier de mots classés selon leur valeur en points (style Scrabble)
Pour cela j'utilise une map avec la valeur en points dans first et les mots dans second.
Or plusieurs mots différents peuvent avoir le même score j'ai donc mis les mots du second dans un set.
J'ai donc std::map<unsigned, std::set<std::string> > dico;
Cependant quand je l'utilise ça ne me met dans mon fichier que les deux premiers mots (ceux avec les deux valeurs les plus importantes) mais indéfiniment, le programme génère toujours les deux même lignes...
Merci d'avance à qui saurait me dire où je me suis trompé !
Je dispose de deux fonctions et de deux flux correctement ouverts :
J'essaye de générer un fichier de mots classés selon leur valeur en points (style Scrabble)
Pour cela j'utilise une map avec la valeur en points dans first et les mots dans second.
Or plusieurs mots différents peuvent avoir le même score j'ai donc mis les mots du second dans un set.
J'ai donc std::map<unsigned, std::set<std::string> > dico;
Cependant quand je l'utilise ça ne me met dans mon fichier que les deux premiers mots (ceux avec les deux valeurs les plus importantes) mais indéfiniment, le programme génère toujours les deux même lignes...
Merci d'avance à qui saurait me dire où je me suis trompé !
Je dispose de deux fonctions et de deux flux correctement ouverts :
std::string enMaj(std::string); unsigned valeur(std::string); std::ifstream f_in(argv[1], std::ios::in); std::ofstream f_out(argv[2], std::ios::out | std::ios::trunc);Et voici le code de mon programme principal :
std::map<unsigned, std::set<std::string> > dico; std::string s_in, s_out ,s_trash; std::getline(f_in,s_trash,'\n'); // suppression de la première ligne // insertion des données while (!f_in.eof()) { std::getline(f_in,s_in,'\t'); // on ne récupère que le premier champ std::getline(f_in,s_trash,'\n'); s_out=enMaj(s_in); dico[valeur(s_out)].insert(s_out+"|"+s_in); // format "MOT|mot" } // parcours par ordre décroissant des clés std::map<unsigned, std::set<std::string> >::const_reverse_iterator i(dico.rbegin()), n(dico.rend()); for(;i!=n;i--) { // parcours par ordre croissant des mots pour chaque clé std::set<std::string>::const_iterator j(i->second.begin()), m(i->second.end()); for(;j!=m;j++) f_out << *j << '\n'; }
A voir également:
- C++ set vs map
- STL-DMX - Télécharger - Création musicale
- Decodeur tnt cgv etimo stl 2 - Guide
6 réponses
Oulala c'est bien exotique comme manière de faire. Si tu veux trier tes mots des meilleurs en nombre de points au plus mauvais, il vaut mieux spécifier le paramètre template de ta std::map et utiliser std::greater au lieu de std::less (qui est le paramètre template par défaut).
... ce qui donne à l'exécution :
Pour ouvrir un fichier en lecture ou en écriture, inutile de t'embêter avec les flags, tu contrôles juste si le std::ostream ou le std::istream sont correctement créés (et tu ne les fermes que dans ce cas).
Au cas où, une petite fiche sur la STL et les différents iterator présents dans la STL :
https://forums.commentcamarche.net/forum/affich-37604421-introduction-a-la-stl-en-c-standard-template-library
Bonne chance
#include <map> #include <set> #include <iostream> #include <string> typedef std::map< unsigned, std::set<std::string>, std::greater<unsigned> > map_valeur_mots_t; int main(){ map_valeur_mots_t map_valeur_mots; map_valeur_mots[10].insert("plop"); map_valeur_mots[10].insert("pouet"); map_valeur_mots[10].insert("tapir"); map_valeur_mots[ 9].insert("banane"); map_valeur_mots[15].insert("pedoncule"); map_valeur_mots_t::const_iterator map_valeur_mots_it (map_valeur_mots.begin()), map_valeur_mots_end(map_valeur_mots.end()); for(;map_valeur_mots_it!=map_valeur_mots_end;++map_valeur_mots_it){ const unsigned & valeur = map_valeur_mots_it->first; const std::set<std::string> & mots = map_valeur_mots_it->second; std::set<std::string>::const_iterator mots_it (mots.begin()), mots_end(mots.end()); for(;mots_it!=mots_end;++mots_it) std::cout << valeur << '\t' << *mots_it << std::endl; } return 0; }
... ce qui donne à l'exécution :
15 pedoncule 10 plop 10 pouet 10 tapir 9 banane
Pour ouvrir un fichier en lecture ou en écriture, inutile de t'embêter avec les flags, tu contrôles juste si le std::ostream ou le std::istream sont correctement créés (et tu ne les fermes que dans ce cas).
#include <fstream> #include <iostream> int main(){ const char *filename_out = "pouet.txt"; // j'ouvre le fichier et vérifie que tout s'est bien passé std::ofstream ofs(filename_out); if(!ofs){ std::cerr << "can't write in " << filename_out << std::endl; return 1; } // le fichier est ouvert avec succès, j'écris dedans ofs << "j'aime les tapirs" << std::endl; // quand j'ai fini : ofs.close(); return 0; }
Au cas où, une petite fiche sur la STL et les différents iterator présents dans la STL :
https://forums.commentcamarche.net/forum/affich-37604421-introduction-a-la-stl-en-c-standard-template-library
Bonne chance
Pour débugger, j'ai simplifié mes fonctions
Il est bien évident que ma boucle infinie est dans l'imbrication de mes deux boucles for, mais je n'arrive pas à comprendre pourquoi (je n'exclue pas la possibilité d'un problème dans la boucle while)
Mon code est assez court et je l'ai regardé dans tous les sens sans résultat, ça doit être une subtilité des itérateurs qui m'échappe...
Si quelqu'un a le début d'une idée qu'il/elle la fasse partager, merci !
std::string enMaj(std::string s) { return s; } unsigned valeur(std::string s) { return s.length(); }Et comme fichier d'entrée je me suis limité à quelques mots :
1_saison 2_date printemps 20/21 mars été 20/21 juin automne 22/23 septembre hiver 21/22 décembreMais là encore même problème, seuls les deux mots avec les plus grandes valeurs sont indéfiniment répétés dans le fichier (ici : printemps, automne, printemps, automne...).
Il est bien évident que ma boucle infinie est dans l'imbrication de mes deux boucles for, mais je n'arrive pas à comprendre pourquoi (je n'exclue pas la possibilité d'un problème dans la boucle while)
Mon code est assez court et je l'ai regardé dans tous les sens sans résultat, ça doit être une subtilité des itérateurs qui m'échappe...
Si quelqu'un a le début d'une idée qu'il/elle la fasse partager, merci !
Merci ça marche !
J'ai pas compris pourquoi ma méthode tournait en boucle, mais j'ai compris celle-ci...
J'ai pas compris pourquoi ma méthode tournait en boucle, mais j'ai compris celle-ci...
C'est normal tu décrémentais tes const_reverse_iterators au lieu de les incrémenter ! Incrémenter un iterator c'est le faire avancer dans le sens décrit par son type (c'est-à-dire de begin/rbegin vers end/rend).
Bonne continuation
Bonne continuation
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Tout s'explique alors, mais comme j'avais vu -- sur l'article de la STL j'avais bêtement fait --
Maintenant que tu as modifié l'article, c'est marqué ++ alors à l'avenir je ferais ++
Encore merci !
Maintenant que tu as modifié l'article, c'est marqué ++ alors à l'avenir je ferais ++
Encore merci !
En fait sur l'ancienne version il y avait marqué que -- décrementait le (reverse_)iterator ce qui revient à le faire reculer, mais la phrase était effectivement très mal tournée. Grâce à ton message, j'ai corrigé tout ça !
Note que l'opérateur -- s'applique également aux iterators ordinaires.
Bonne continuation
Note que l'opérateur -- s'applique également aux iterators ordinaires.
Bonne continuation