[C++] STL : map et set

Résolu/Fermé
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 - 25 août 2009 à 17:33
mamiemando Messages postés 33073 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 avril 2024 - 27 août 2009 à 14:11
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 :
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';
}

6 réponses

mamiemando Messages postés 33073 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 avril 2024 7 748
27 août 2009 à 01:19
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).
#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
2
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
26 août 2009 à 19:35
Pour débugger, j'ai simplifié mes fonctions
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écembre
Mais 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 !
0
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
27 août 2009 à 09:55
Merci ça marche !
J'ai pas compris pourquoi ma méthode tournait en boucle, mais j'ai compris celle-ci...
0
mamiemando Messages postés 33073 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 avril 2024 7 748
27 août 2009 à 10:31
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
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
27 août 2009 à 13:24
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 !
0
mamiemando Messages postés 33073 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 16 avril 2024 7 748
27 août 2009 à 14:11
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
0