IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

Fonction rand() avec exclusion de nombre


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Fonction rand() avec exclusion de nombre
    Bonsoir à tous,

    J'ai débuté Perl il y a de ça peu de temps et j'ai une question.

    Comment dire à la fonction rand() de générer un nombre aléatoire compris entre 1 et 49 mais en excluant le fait qu'il puisse tomber sur un des nombres déja présents dans mon tableau @tableau ?

    Pour bien situer le contexte, voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/usr/bin/perl -w
     
    use strict;
    use warnings;
     
    # Variables
    my ($range_max,$range_min) = (49,1);
    my @tableau = ();
    my $compteur = 0;
     
    # Affiche 5 chiffres (de 1 à 49)
    for (my $i=0; $i<5; $i++) {
    $tableau[$compteur] = int(rand($range_max)) + $range_min;
    print $tableau[$compteur]." ";
    $compteur++;
    }
    J'ai un gros manque de méthodologie pour résoudre ce problème. Je ne sais malheureusement pas COMMENT procéder...

    Merci par avance pour vos réponses

    Cordialement, Clement.

  2. #2
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Bonsoir,

    pour tirer 5 nombres aléatoires compris entre 1 et 49 (sans conditions d'unicité des tirages), je réécrirais ton code de façon plus perlienne comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    my ($range_max, $range_min) = (49, 1);
    my @tableau;
    for (1..5) {
        push @tableau, int(rand($range_max)) + $range_min;
    }
    print "@tableau\n";
    Mais si tu veux des tirages uniques, alors une boucle for n'est sans doute pas une bonne idée, parce que tu ne peux pas savoir à l'avance si tu va tirer des doublons ou non. Il vaut mieux utiliser une boucle while et reboucler tant que tu n'as pas le nombre voulu de nombres. Pour vérifier si tu tombes sur un nombre déjà tiré, le mieux est de stocker les tirages obtenus dans un hachage et de vérifier à chaque fois si l'on a déjà vu le nombre tiré; du coup, autant stocker les nombres directement dans un hachage au lieu d'un tableau.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    my ($range_max, $range_min) = (49, 1);
    my %tirages;
    my $nb_el = 5;
    while ($nb_el) {
        my $random = int(rand($range_max)) + $range_min;
        if (not exists $tirages{$random}) {
            $tirages{$random} = 1;
            $nb_el--;
        }
    }
    print "$_ " for keys %tirages;
    Là, j'ai décomposé les étapes pour assurer le maximum de clarté, mais j'écrirais sans doute la boucle while de façon un peu plus concise:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    while ($nb_el) {
        my $random = $range_min + int rand $range_max;
        $tirages{$random} = 1 and $nb_el-- unless exists $tirages{$random};
    }
    PS: indente systématiquement ton code de façon cohérente, ça te fera gagner un temps fou pour éviter des bugs sournois. Il n'est pas nécessaire d'indenter le code pour que le compilateur comprenne, mais c'est nécessaire pour que toi et moi comprenions bien. Bref, indenter le code n'est pas facultatif, c'est indispensable et essentiel.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour Lolo78,

    D'accord, ma logique n'était pas bonne. Je trouve ça utile de pouvoir comparer plusieurs version de code mais je dois avouer que la version clarifiée m'a le plus aidé pour comprendre la résolution de mon problème.

    Citation Envoyé par Lolo78 Voir le message
    PS: indente systématiquement ton code de façon cohérente, ça te fera gagner un temps fou pour éviter des bugs sournois. Il n'est pas nécessaire d'indenter le code pour que le compilateur comprenne, mais c'est nécessaire pour que toi et moi comprenions bien. Bref, indenter le code n'est pas facultatif, c'est indispensable et essentiel.
    J'ai pris note du conseil

    Je te remercie beaucoup, tes exemples m'auront été utiles !

    Topic résolu !

  4. #4
    Membre chevronné
    Avatar de Schmorgluck
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    371
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2006
    Messages : 371
    Par défaut
    Désolé de relancer un sujet marqué comme résolu, mais j'ai des objections sur la façon dont il a été résolu. Il y a des questions implicites qui méritent des réponses plus approfondies.

    Jesarey, tu débarques visiblement en Perl en provenance du C ou d'un langage proche, ça se voit à ton usage de la boucle for (la syntaxe à trois termes on l'utilise très peu en Perl au bout du compte). Rien de mal à ça, j'ai fait pareil en mon temps. Comme beaucoup de gens. Du coup, tu raisonnes encore en termes de C. Tu passes à côté des facilités que Perl offre.

    Il s'agit d'un problème classique de tirage sans remise. Selon les langages et ce qu'ils offrent comment structures de bases, ou ce qui est disponible comme modules ou bibliothèques, c'est plus ou moins facile à implémenter, mais rarement très difficile, à condition de bien reformuler le problème dans la logique disponible.

    Dans un langage comme Perl, le tableau est un type de base et, en plus, on n'a pas à se soucier de la façon dont il est géré dans la soute. Dans certains langages, j'utiliserais une liste chaînée (en C par exemple), ou un objet "ensemble" (en C++ par exemple) ou que sais-je. En Perl, le tableau est une structure de base prédéfinie, et c'est probablement une liste chaînée derrière, ou quelque chose de similaire, mais dans la pratique je m'en fous, ce qui m'intéresse c'est qu'une fonction de base du langage, splice me permet d'en retirer un élément à n'importe quelle position tout en retournant ledit élément. Et pour le problème spécifique de ce thread, un tirage de cinq éléments dans un ensemble de quarante-neuf, c'est vraiment tout ce dont nous avons besoin pour une solution élégante et plutôt simple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    #! /usr/bin/perl
    use strict;
    use warnings;
     
    my @urne = (1..49);
     
    my $quantite = 5;
     
    my @tirage=();
     
    for (1..$quantite)
    {
    	my $cardinal= @urne ;
    	push @tirage,splice (@urne,rand $cardinal,1);
    }
    print "$_\n" for @tirage;
    Voilà, c'est beaucoup plus "Perl way" comme ça. Et on peut remplacer le contenu de @urne par n'importe quoi, ça marche tout pareil. Il faut cependant garder à l'esprit que @urne est altéré, donc on peut avoir besoin de le cloner pour éviter des effets de bord indésirables.

    Attention, je n'invalide pas la solution proposée par Lolo78 pour autant. Elle est valide. Elle est même plus pertinente que la mienne pour un tirage dans un très très grand ensemble d'entiers consécutifs.

    J'ai cherché sur le CPAN, mais je n'ai pas trouvé de module pour ce problème. J'ai peut-être pas trouvé quels mots-clés utiliser, ou le problème est trop simple pour mériter un module, je ne sais pas.

    Si je puis me permettre de faire mon chieur une seconde, je tiens à signaler que je déteste cette ligne de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my ($range_max, $range_min) = (49, 1);
    Saurez vous deviner pourquoi ?

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour Schmorgluck,

    Merci à toi pour ton intervention. J'ai pris note de ton code. La fonction splice (que je ne connaissait pas auparavant) est vraiment intéressante et surtout adapté pour ce genre de contexte.

    Citation Envoyé par Schmorgluck Voir le message
    Si je puis me permettre de faire mon chieur une seconde, je tiens à signaler que je déteste cette ligne de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my ($range_max, $range_min) = (49, 1);
    Saurez vous deviner pourquoi ?
    My bad. Le nom de la variable $range_max a vraiment mal été choisie. D'après ce que je comprend, le résultat que procure la variable $range_max peut correspondre au maximum à $range_max + $range_min. Donc mettre ce nom pour cette variable est illogique.

    Enfin, corrige-moi si je me trompe Schmorgluck !

  6. #6
    Membre chevronné
    Avatar de Schmorgluck
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    371
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2006
    Messages : 371
    Par défaut
    C'est juste que je préférerais cette version-là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my ($range_min, $range_max) = (1,49);
    Mais c'est vraiment parce que j'ai envie de pinailler.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Utilisation de la Fonction Rand () avec des conditions
    Par Karamus dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 25/10/2014, 17h11
  2. Fonction rand rend le meme nombre
    Par kimymet dans le forum C
    Réponses: 5
    Dernier message: 27/04/2012, 18h35
  3. [SQL] PHP/SQL Rand avec exclusion
    Par snaxisnake dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 01/01/2008, 18h31
  4. Réponses: 7
    Dernier message: 05/05/2006, 09h48
  5. Fonction Execlp avec nombre parametres variable
    Par laurent_ifips dans le forum C
    Réponses: 3
    Dernier message: 25/11/2005, 20h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo