Problème sur la table de hashage [Résolu/Fermé]

Signaler
-
 laisso -
Bonjour,

J'ai des difficultés pour exécuter les questions 4 5 et 6. Merci de bien vouloir m'aiguiller.


#Construire un programme proposant ces fonctionnalités :


#* Au chargement, on a au moins 4 abonnés dont un à 0 DVD et un à undef.

#* On boucle sur un menu proposant :




#1. afficher la DVDthéque
#2. ajouter un abonné
#3. supprimer un abonné
#4. emprunt d'un ou plusieurs DVD
#5. retour d'un ou plusieurs DVD
#6. quitter



#On aidera l'utilisateur à tout moment du mieux qu'on peut, exemples (non exhaustifs) :




#* 2 : on affiche la liste des abonnés pour lui montrer ceux qui existent déjà. On vérifie que le nouvel entrant n'existe pas sinon, message.
#* 3 : on affiche la liste des abonnés avec des numéros pour qu'il puisse indiquer rapidement celui qu'il veut supprimer. On boucle sur une saisie blindée sur ces numéros-là.
#* 4 : la liste des abonnés est affichée comme ci-dessus.
#* 5 : idem ci-dessus et on vérifie qu'un abonné ne peut pas rendre plus de DVD qu'il n'en a.


#!/usr/bin/perl

# La liste des emprunteurs est donnée par une table de hachage %abonnes

# Clé : indentifiant = prénom pour simplifier

# Valeur : nb de DVD empruntés

# Création de la table :

$abonnes{"Guillaume"} = 3;
$abonnes{"Maxime"} = 15;
$abonnes{"Anne"} = 0; # abonné qui a déjà emprunté mais aucun emprunt en cours
$abonnes{"Michel"} = undef;

# Affichage

print("\n\nAffichage de la DVDthèque");
while (($prenom,$nbDVD) = each %abonnes) {
print "\n$prenom est abonné";
# si le nb de DVD n'est pas undef
if (defined($nbDVD)) {
print("\n\tnb de DVD empruntés : $nbDVD");
} else {
print("\n\tIl n'a jamais emprunté de DVD");
}
}

# Ajout d'un nouvel abonné sans emprunt

print("\n\nAjout d'un nouvel abonné sans emprunt");
print("\nQui souhaitez-vous ajouter ? ");
$newAbonne =<STDIN>;
chomp($newAbonne); # suppression du saut de ligne
$abonnes{"$newAbonne"} = undef; # abonné sans emprunt

# Affichage

print("\n\nAffichage de la DVDthèque");
while (($prenom,$nbDVD) = each %abonnes) {
print("\n$prenom est abonné");
# si le nb de DVD n'est pas undef
if (defined($nbDVD)) {
print("\n\tnb de DVD empruntés : $nbDVD");
} else {
print("\n\tIl n'a jamais emprunté de DVD");
}
}

# Révocation d'un abonné : delete

print("\n\nQuel User souhaitez vous supprimer?");
$user= <>;
chomp($user);
delete ($abonnes {$user}) ;

# Affichage

print("\n\nAffichage de la DVDthèque");
while (($prenom,$nbDVD) = each %abonnes) {
print("\n$prenom est abonné");
# si le nb de DVD n'est pas undef
if (defined($nbDVD)) {
print("\n\tnb de DVD empruntés : $nbDVD");
} else {
print("\n\tIl n'a jamais emprunté de DVD");
}
}

# Emprunt d'un ou plusieurs DVD

print("\n\nCombien de DVD voulez vous emprunter?");
$maxDVD = -1; # le max de DVD empruntés
while (($prenom,$nbDVD) = each %abonnes) {
if ($nbDVD > $maxDVD) {
$DVD = $nbDVD;
$Emprunteur = $prenom;
}
}
print("\nIl a emprunté $DVD DVD");

# Recherche d'un abonné

print("\n\nQuel abonné cherchez-vous ? ");
$abbX = <STDIN>;
chomp($abbX); # suppression du saut de ligne
if (exists $abonnes{$abbX}) {
print("\n$abbX est abonné\nIl a emprunté $abonnes{$abbX} DVD");
} else {
print("\n$abbX n'est pas abonné\n");
}


# retour d'un ou plusieurs DVD

print'"\n\nCombien de DVD coulez vous restituer?");
while (($prenom,$nbDVD) = each %abonnes) {
if ($nbDVD > $maxDVD) {
$DVD = $nbDVD;
$restitué = $prenom;
}
}
print ("\nIl a restitué $DVD DVD");

# Quitter

print("\n\nAu revoir\n\n");

1 réponse

Messages postés
5550
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
12 mai 2021
934
Salut laisso,

Ton code Perl ne compile pas, car :

- à cette ligne
print'"\n\nCombien de DVD coulez vous restituer?"); 
, tu as une
'
à la place d'une
(
...
... et plus bas...
- tu as un accent sur cette variable
$restitué = $prenom; 
(que tu n'utilises d'ailleurs pas dans ton code)

En outre, tu ne fais pas ce que te demande de faire l'énoncé de l'exercice, qui te demande de créer un menu avec une boucle permettant d'afficher les différentes options du programme et de les exécuter en sélectionnant leur numéro.

Pareil pour la suppression : on te demande d'afficher la liste des différents abonnés avec des numéros pour que l'utilisateur puisse indiquer en tapant le numéro qui il veut supprimer, en bouclant tant qu'une saisie invalide est faite.

Par exemple :

Qui voulez-vous supprimer :

1. Guillaume
2. Maxime
3. Anne
4. Michel
0. Retour au menu principal


En fait, on te demande de faire une interface utilisateur (textuelle) pour que l'utilisateur sache ce qu'il peut faire avec le programme et lui faciliter la vie.

Tu devrais faire des fonctions pour chaque fonctionnalité de ton programme.

Pour tes questions "J'ai des difficultés pour exécuter les questions 4 5 et 6. Merci de bien vouloir m'aiguiller."

j'imagine que cela correspond aux items suivant du menu principal :

#4. emprunt d'un ou plusieurs DVD
#5. retour d'un ou plusieurs DVD
#6. quitter


Si le programme se limite à comptabiliser le nombre d'ouvrages empruntés, j'imagine qu'il suffit :

- pour 4 : d'incrémenter la valeur correspondant à la personne dans le hash qui emprunte,
- pour 5 : de décrémenter
- pour 6 : tu termines ton programme : exit parait indiqué si tu es dans une boucle

Votre enseignant ne vous a pas enseigné à utiliser les directives strict et warnings ?

Dal
1
Merci

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 65492 internautes nous ont dit merci ce mois-ci

Pour le choix 5 j'ai ce message d'erreur que je ne comprends pas

Use of uninitialized value $maxDVD in numeric gt (>) at perl.pl line 90, <STDIN> line 1.
Use of uninitialized value $n in subtraction (-) at perl.pl line 93, <STDIN> line 1.
Use of uninitialized value $maxDVD in numeric gt (>) at perl.pl line 90, <STDIN> line 1.
Modification of non-creatable array value attempted, subscript -2 at perl.pl line 88, <STDIN> line 1.
Pour le choix 4, J'ai ce message

Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3.
Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3.
Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3.
Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3
Merci de votre aide!




#!/usr/bin/perl
use strict;
use warnings;

my $i=0;
my @DVD;
my $emprunteur;
my $prenom;
my $n;
my %abonnes;
my $nbDVD;
my $newAbonne;
my $user;
my $maxDVD;
my $DVD;
my $restituer;

# La liste des emprunteurs est donnée par une table de hachage %abonnes
# Clé : indentifiant = prénom pour simplifier
# Valeur : nb de DVD empruntés
# Création de la table :

$abonnes{"Guillaume"} = 3;
$abonnes{"Maxime"} = 15;
$abonnes{"Anne"} = 0; # abonné qui a déjà emprunté mais aucun emprunt en cours
$abonnes{"Michel"} = 0;

while (1){
print "################## Menu ##################\n";
print "# #\n";
print "# 1 - Affichage de la DVDthéque #\n";
print "# 2 - Ajoute d'un abonné #\n";
print "# 3 - Suppression d'un abonné #\n";
print "# 4 - Emprunt de DVD #\n";
print "# 5 - Retour de DVD #\n";
print "# 6 - Quitter #\n";
print "# #\n";
print "##########################################\n";
print "choix : ";
my $choix=<STDIN>;

if ( $choix == 1 ){
print("\n\nAffichage de la DVDthèque" );
while (($prenom,$nbDVD) = each %abonnes) {
print "\n$prenom est abonne";
# si le nb de DVD n'est pas undef
if (defined($nbDVD)) {
print("\n\tnb de DVD empruntes : $nbDVD" );
} else {
print("\n\tIl n'a jamais emprunte de DVD" );
}
}
}
elsif ( $choix == 2 ){
# Ajout d'un nouvel abonné sans emprunt
print("\n\nAjout d'un nouvel abonné sans emprunt" );
print("\nQui souhaitez-vous ajouter ?" );
$newAbonne =<STDIN>;
chomp($newAbonne); # suppression du saut de ligne
$abonnes{"$newAbonne"} = undef; # abonné sans emprunt
}
elsif ( $choix == 3 ){
# Révocation d'un abonné : delete
print("\n\nQuel User souhaitez vous supprimer?" );
$user= <>;
chomp($user);
delete ($abonnes {$user}) ;
}
elsif ( $choix == 4 ){
# Emprunt d'un ou plusieurs DVD
print("\n\nCombien de DVD voulez vous emprunter?" );
$maxDVD = -1; # le max de DVD emprunter
while (($prenom,$nbDVD) = each %abonnes) {
$DVD[$i]=$user;
$i++;
if ($nbDVD > $maxDVD) {
$DVD = $nbDVD;
$emprunteur = $prenom;
$abonnes{$emprunteur} = $abonnes{$emprunteur} + $n;
}
}
print("\nIl a emprunte $DVD DVD" );
}
elsif ( $choix == 5 ){
# retour d'un ou plusieurs DVD
print"\n\nCombien de DVD voulez vous restituer?";
while (($prenom,$nbDVD) = each %abonnes) {
$DVD[$i]=$user;
$i--;
if ($nbDVD > $maxDVD) {
$DVD = $nbDVD;
$restituer = $prenom;
$abonnes{$restituer} = $abonnes{$restituer} - $n;
}
}
print ("\nIl a restitue $DVD DVD" );
}
elsif ( $choix == 6 ){
exit 0;
}
else{
print "Votre choix n'est pas dans ceux proposes\n";
}
}
Messages postés
5550
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
12 mai 2021
934
laisso,

1.

Je n'avais pas répondu à ton précédent message car tu repostais un code qui ne compilait pas, ne déclarant pas les variables, et qui ne tenait pas compte de mes observations.

Celui que tu postes compiles désormais, les erreurs étant seulement signalées à l'exécution, merci d'avoir fait cet effort :-)

Stp, lorsque tu postes du code, mets le entre balises code, comme ceci :

<code perl>
   print "Hello\n";
</code>
Cela va colorer la syntaxe de ton code, préserver l'indentation de ce que tu postes et numéroter les lignes. Cela est plus lisible sur le forum.

Ton code ne tient cependant toujours pas compte de toutes mes précédentes observations.

Sois attentif, stp, car je ne vais pas me répéter indéfiniment.

2.

Pour :

Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3.
Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3.
Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3.
Use of uninitialized value $n in addition (+) at perl.pl line 79, <STDIN> line 3


Cela correspond à ceci :

    elsif ( $choix == 4 ){
# Emprunt d'un ou plusieurs DVD
        print("\n\nCombien de DVD voulez vous emprunter?" );
        $maxDVD = -1; # le max de DVD emprunter
        while (($prenom,$nbDVD) = each %abonnes) {
            $DVD[$i]=$user;
            $i++;
            if ($nbDVD > $maxDVD) {
                $DVD = $nbDVD;
                $emprunteur = $prenom;
                $abonnes{$emprunteur} = $abonnes{$emprunteur} + $n;
            }
        }
        print("\nIl a emprunte $DVD DVD" );
    }


et plus particulièrement à la ligne
$abonnes{$emprunteur} = $abonnes{$emprunteur} + $n;
dans laquelle tu additionnes
$n
alors que
$n
n'est initialisé à rien de particulier. Tu t'es contenté de le déclarer, mais Perl t'avertit que tu n'y a rien mis (grâce à
use warnings
).

Cela rejoint une autre observation que j'ai déjà faite sur ce code :

Hormis ce problème, une chose est sûre : le programme ne sais pas qui emprunte, car il ne demande pas cette information à l'utilisateur (en affichant la liste et en invitant l'utilisateur à indiquer qui est la personne concernée).

Ton algorithme est faux, et comme déjà indiqué, je ne comprends pas du tout ton code, ou ce que tu essayes de faire.

A mon sens, ce que tu dois faire c'est :

- afficher la liste des abonnés
- demander à l'utilisateur du programme quel est l'abonné qui veut emprunter un livre
- demander à l'utilisateur du programme combien de livres l'abonné veut emprunter
- s'il y a un maximum de livres qu'un abonné donné peut emprunter, en tenir compte (ton énoncé n'indique pas cette information, cependant)
- si l'emprunt est permis, incrémenter la valeur correspondant au nombre de livres que cette personne a emprunté du nombre de livres nouvellement empruntés

3.

pour :

Use of uninitialized value $maxDVD in numeric gt (>) at perl.pl line 90, <STDIN> line 1.
Use of uninitialized value $n in subtraction (-) at perl.pl line 93, <STDIN> line 1.
Use of uninitialized value $maxDVD in numeric gt (>) at perl.pl line 90, <STDIN> line 1.
Modification of non-creatable array value attempted, subscript -2 at perl.pl line 88, <STDIN> line 1.


Cela correspond à ceci :

    elsif ( $choix == 5 ){
# retour d'un ou plusieurs DVD
        print"\n\nCombien de DVD voulez vous restituer?";
        while (($prenom,$nbDVD) = each %abonnes) {
            $DVD[$i]=$user;
            $i--;
            if ($nbDVD > $maxDVD) {
                $DVD = $nbDVD;
                $restituer = $prenom;
                $abonnes{$restituer} = $abonnes{$restituer} - $n;
            }
        }
        print ("\nIl a restitue $DVD DVD" );
    }


Les erreurs signalées à l'exécution sont dues au fait que la valeur de $i est décrémentée et tu te retrouves avec des indices négatifs, et que, par ailleurs, $maxDVD et $n ne sont pas initialisés.

là aussi, ton algorithme est faux, tout est à revoir, tu dois :

- afficher la liste des abonnés
- demander à l'utilisateur du programme quel est l'abonné qui veut restituer un livre
- demander à l'utilisateur du programme combien de livres l'abonné veut restituer
- éventuellement faire un contrôle de cohérence pour vérifier qu'il ne restitue pas plus de livres qu'il n'est sensé avoir déjà emprunté, s'il y a une erreur, traiter l'erreur (sois créatif) : renvoyer une erreur et arrêter le programme, ou renvoyer une erreur et demander une nouvelle saisie, ou renvoyer une erreur et revenir au menu principal, etc.
- si l'information est cohérente, traiter la restitution en décrémentant la valeur correspondant au nombre de livres que cette personne a emprunté du nombre de livres désormais restitués

Ta boucle n'a aucune raison d'être, et ton tableau ne sert à rien.

4.

Si tu veux vraiment utiliser un tableau et une boucle en complément de ton hash, d'une façon qui ait un sens par rapport à l'énoncé, tu peux le faire pour présenter la liste des abonnés précédée d'un numéro, permettant à l'utilisateur de taper un numéro pour choisir un abonné, au lieu d'avoir à taper son nom.

Voilà un exemple, avec une fonction réutilisable à cet effet :

#!/usr/bin/perl

use strict;
use warnings;

my %abonnes;

$abonnes{"Guillaume"} = 3;
$abonnes{"Maxime"} = 15;
$abonnes{"Anne"} = 0; # abonné qui a déjà emprunté mais aucun emprunt en cours
$abonnes{"Michel"} = undef;

sub select_a_subscriber {
    my (%hash) = @_;
    my @arr;
    my $n;
    my $select = 0;
    foreach my $key (sort keys %hash) {
        push @arr, $key;
        print ++$n . ". $key\n";                                                                        
    }
    while (($select < 1) || ($select > $n)) {
        print "Sélection (1 à $n) ? \n";
        $select = <>;
        chomp($select);
    }
    return $arr[$select - 1];
}

my $ab = select_a_subscriber(%abonnes);
print "Abonné sélectionné : $ab\nNombre d'ouvrages empruntés : ";
defined $abonnes{$ab} ? print "$abonnes{$ab}\n" : print "jamais emprunté d'ouvrages\n";


cela donne, par exemple :

1. Anne
2. Guillaume
3. Maxime
4. Michel
Sélection (1 à 4) ?
3
Abonné sélectionné : Maxime
Nombre d'ouvrages empruntés : 15

Les noms sont, en outre, classés par ordre alphabétique.

Cela te permet de combiner la souplesse du hash, avec l'indexation séquentielle permise par le array, et de répondre à la demande qui t'est faite (on affiche la liste des abonnés avec des numéros pour qu'il puisse indiquer rapidement).

Est-ce toi qui a pris l'initiative d'utiliser un hash pour stocker les données, ou est-ce une demande qui t'est faite et qui n'est pas apparente dans l'énoncé que tu donnes ?

Comme déjà dit précédemment, tu devrais faire des fonctions Perl pour exécuter les différentes parties de ton code, surtout les parties réutilisables, mais aussi les autres.

Un switch / case te permettrait de présenter la logique de la totalité de ton programme en un écran.

http://perldoc.perl.org/5.8.8/Switch.html

Cela présente aussi l'avantage de t'éviter de créer des variables globales, avec les risques que cela représente, pour des variables dont tu n'as un usage que dans une partie de ton code, désormais encapsulé dans une fonction. Cela réduit la portée de tes variables à la fonction qui les utilise, et évite de mauvaises surprises.

Et puis, de toutes façons, c'est une bonne pratique de séparer


Dal
>
Messages postés
5550
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
12 mai 2021

Bonjour,

J'ai réussi à trouver un code capable de faire ce que je lui demande. J'aurais besoin que vous m'aidiez à l'optimiser svp?

#!/usr/bin/perl
use strict;
use warnings;

my $i=0;
my @DVD;
my $emprunteur;
my $prenom;
my $n=0;
my %abonnes;
my $nbDVD;
my $newAbonne;
my $user;
my $maxDVD=-1;
my $restituer;
my $abonnes;
my $DVD;

# La liste des emprunteurs est donnée par une table de hachage %abonnes
# Clé : indentifiant = prénom pour simplifier
# Valeur : nb de DVD empruntés
# Création de la table :
$abonnes{"Guillaume"} = 3;
$abonnes{"Maxime"} = 15;
$abonnes{"Anne"} = 0; # abonné qui a déjà emprunté mais aucun emprunt en cours
$abonnes{"Michel"} = undef;

while (1){
print "################## Menu ##################\n";
print "# #\n";
print "# 1 - Affichage de la DVDthéque #\n";
print "# 2 - Ajoute d'un abonné #\n";
print "# 3 - Suppression d'un abonné #\n";
print "# 4 - Emprunt de DVD #\n";
print "# 5 - Retour de DVD #\n";
print "# 6 - Quitter #\n";
print "# #\n";
print "##########################################\n";
print "choix : ";
my $choix=<STDIN>;

if ( $choix == 1 ){
print("\n\nAffichage de la DVDthèque" );
while (($prenom,$nbDVD) = each %abonnes) {
print "\n$prenom est abonne";
# si le nb de DVD n'est pas undef
if (defined($nbDVD)) {
print("\n\tnb de DVD empruntes : $nbDVD" );
} else {
print("\n\tIl n'a jamais emprunte de DVD" );
}
}
}
elsif ( $choix == 2 ){
# Ajout d'un nouvel abonné sans emprunt
print("\n\nAjout d'un nouvel abonné sans emprunt" );
print("\nQui souhaitez-vous ajouter ?" );
$newAbonne =<STDIN>;
chomp($newAbonne); # suppression du saut de ligne
$abonnes{"$newAbonne"} = undef; # abonné sans emprunt
}
elsif ( $choix == 3 ){
# Révocation d'un abonné : delete
print("\n\nQuel User souhaitez vous supprimer?" );
$user= <>;
chomp($user);
delete ($abonnes {$user}) ;
}
elsif ( $choix == 4 ){
# Emprunt d'un ou plusieurs DVD

sub select_a_subscriber {
my (%hash) = @_;
my @arr;
my $n;
my $select = 0;
foreach my $key (sort keys %hash) {
push @arr, $key;
print ++$n . ". $key\n";
}
while (($select < 1) || ($select > $n)) {
print "Sélection (1 à $n) ? \n";
$select = <>;
chomp($select);
}
return $arr[$select - 1];
}
my $ab = select_a_subscriber(%abonnes);

print("\n\nCombien de DVD voulez vous emprunter?" );
{
if ($nbDVD > $maxDVD) {
$DVD = <>;
$DVD[$i]=$user;
$i++;
$emprunteur = $prenom;
$abonnes{$emprunteur} = $abonnes{$emprunteur} + $n;
}
}
print("\nil a emprunte $DVD DVD" );
}

elsif ( $choix == 5 ){
# retour d'un ou plusieurs DVD

sub select_a_subscriber {
my (%hash) = @_;
my @arr;
my $n;
my $select = 0;
foreach my $key (sort keys %hash) {
push @arr, $key;
print ++$n . ". $key\n";
}
while (($select < 1) || ($select > $n)) {
print "Sélection (1 à $n) ? \n";
$select = <>;
chomp($select);
}
return $arr[$select - 1];
}

my $ab = select_a_subscriber(%abonnes);
print"\n\nCombien de DVD voulez vous restituer?";
{
if ($nbDVD > $maxDVD) {
$DVD = <>;
$DVD[$i]=$user;
$i--;
$DVD = $nbDVD;
$restituer = $prenom;
$abonnes{$restituer} = $abonnes{$restituer} - $n;
}
}
print ("\nil a restitue $DVD DVD" );
}
elsif ( $choix == 6 ){
exit 0;
}
else{
print "Votre choix n'est pas dans ceux proposes\n";
}
}
Messages postés
5550
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
12 mai 2021
934
Pour poster un code Perl; c'est avec <code perl> pas seulement <code>.

l'intérêt des fonctions est que tu factorises le code, en définissant dans une fonction (sub en Perl) du code utilisé plusieurs fois, pour ne pas avoir à le dupliquer. Là non seulement tu dupliques le code, mais tu dupliques la définition de fonctions.

https://fr.wikibooks.org/wiki/Programmation_Perl/Fonctions_et_proc%C3%A9dures

Ton algorithme est toujours faux pour l'emprunt et la restitution.

tu as le nom de l'abonné dans $ab, tu n'as donc pas besoin de $emprunteur, puisque c'est $ab l'emprunteur.

tu demandes combien de DVD l'abonné veut emprunter, mais tu ne mets pas cette valeur dans $n qui est utilisé pour incrémenter la valeur du hash. Tu utilises $user et $prenom qui sortent de nulle part et dont tu n'as pas besoin, pas plus que $DVD ou @DVD, ou $i. Tu compares des choses avec $nbDVD > $maxDVD qui n'ont pas de sens non plus.

J'ai déjà dit tout cela au moins 3 fois. C'est mon quota :-)

Tout cela m'inspire seulement que tu n'as pas les bases en Perl pour comprendre ce que tu tapes.

Je pense que tu devrais vraiment revoir les bases avec tes cours ou ton manuel.

Je ne peux pas faire cela pour toi.

Bonne chance
>
Messages postés
5550
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
12 mai 2021

J'ai réussi à résoudre mon code. le plus difficile était l'étape 4 et 5.