2
votes

comment rejeter des nombres aléatoires en python?

J'essaie de construire un générateur de numéros de loterie mais je ne sais pas comment faire en sorte que le module aléatoire rejoue le numéro s'il a déjà été généré ou s'il appartient à une liste. Donc, fondamentalement, je veux que les nombres de oldNumbers ne soient pas générés à nouveau. Désolé si je ne suis pas assez explicite mais je laisse le code ici. merci

import random

oldNumbers = [5, 11, 19, 20, 38]

ball1 = random.randint(1, 39)
ball2 = random.randint(1, 39)
ball3 = random.randint(1, 39)
ball4 = random.randint(1, 39)
ball5 = random.randint(1, 39)

print(ball1, ball2, ball3, ball4, ball5)


1 commentaires

Ok, j'ai supprimé ma réponse à cause du commentaire @eyllanesc. Pour ma défense, la question n'était pas explicite en termes de résultat souhaité ou d'échantillon.


3 Réponses :


5
votes

Voici une solution simple:

print(random.sample(set(range(1, 39)) - set(oldNumbers), 5))

ou vous pouvez simplement utiliser la soustraction set :

print(random.sample([i for i in range(1, 39) if i not in oldNumbers], 5))

p >


0 commentaires

0
votes

Il existe deux manières simples. La première consiste à essayer plusieurs fois les nombres aléatoires et à rejeter ceux qui sont dans une liste

import random
oldNumbers = [5, 11, 19, 20, 38]
for i in range(5):
    newNumbers = [i for i in range(1,39) if i not in oldNumbers]
    ball=random.choice(newNumbers)
    print(oldNumbers,ball)
    oldNumbers+=[ball]

L'autre méthode consiste à sélectionner des nombres aléatoires uniquement dans une liste contenant les nombres souhaités.

import random
oldNumbers = [5, 11, 19, 20, 38]
for i in range(5):
    ball=random.randint(1, 39)
    while ball in oldNumbers:
        print('Rejected:',ball)
        ball = random.randint(1, 39)
    print(oldNumbers,ball)
    oldNumbers+=[ball]


0 commentaires

0
votes

La réponse de Selcuk est la meilleure approche pour votre problème, mais j'ai pensé que je proposerais une alternative qui sera plus efficace lorsque la plage est énorme et que oldNumbers n'est pas trop grand.

from itertools import islice
from random import sample

forbidden = set(oldNumbers)

numneeded = 5

# Might have old numbers in it, but definitely has at least 5 new numbers
numbers = random.sample(range(1, 39), numneeded + len(forbidden))

# Generates only the new numbers
notForbidden = (num for num in numbers if num not in forbidden)

# Keep only as many as you need
newNumbers = list(islice(notForbidden, numneeded))

Tout cela (à part les importations) pourrait être une ligne ( newNumbers = list (islice (filterfalse (set (interdit) .__ contient__, random.sample (range (1, 39), 10)), 5)) ) mais je l'ai divisé à titre d'illustration.

Ceci a l'avantage de ne pas avoir besoin de construire une liste filtrée pour passer à sample , qui si range code > est devenu plus gros, pourrait devenir un problème pour le temps d'exécution / la mémoire. Au lieu de cela, vous générez juste assez de nombres pour être sûr d'avoir généré au moins le montant dont vous avez besoin, même si vous sélectionnez tous les nombres interdits, puis gardez-en autant que nécessaire.

Lorsque la réponse de Selcuk est O (n) est la taille de la plage , cette réponse est O (n) dans le nombre de nombres que vous devez générer plus le nombre à exclure (qui doit toujours être inférieur à la taille de la plage pour des raisons évidentes).


5 commentaires

Je pense que le point que @eyllanesc a fait sur ma réponse (supprimé maintenant) s'applique également à votre solution. Ici, le notForbidden doit être utilisé de manière cohérente. Les 5 échantillons ne doivent donc pas être prélevés simultanément. Cela signifie que si [5, 11, 19, 20, 38] est l'ancien numéro de départ, alors le premier nombre aléatoire peut être l'un de ceux-ci, mais ce nombre particulier, disons 11, ne peut pas être généré à nouveau dans les quatre échantillons suivants. Cela signifie également que si le premier échantillon n'est pas dans les oldNumbers, disons 10, alors le deuxième échantillon peut à nouveau être 10 car il n'est pas dans les oldNumbers.


Je cite essentiellement ici OP "Donc, fondamentalement, je veux que les nombres des anciens numéros ne soient pas générés à nouveau." Que je traduis comme ce que j'ai écrit dans mon premier commentaire


@Bazingaa: Ce problème ne s'applique pas. Je génère 10 valeurs uniques (même si seules cinq valeurs finales sont nécessaires), puis je dessine les cinq premières valeurs qui n'étaient pas dans oldNumbers . Puisque je génère des valeurs uniques, il doit y en avoir au moins cinq qui ne sont pas dans oldNumbers , et elles ne seront pas non plus répétées dans newNumbers (car encore une fois, tout 10 sont uniques).


@Bazingaa: Je peux me tromper, mais j'ai interprété "comment faire en sorte que le module aléatoire rejoue le numéro s'il était déjà généré ou appartenait à une liste" pour signifier qu'ils ne voulaient pas générer de nombres à partir de oldNumbers ou nombres déjà générés dans la production des newNumbers (donc si vous générez 10 en premier, vous ne devriez pas le générer pour les choix 2-5). Après tout, c'est un tirage au sort, et d'après ce que je comprends, il n'y a qu'une seule balle avec chaque numéro dessus; si les boules du dernier dessin ne sont pas remises dans la corbeille, vous ne pouvez pas les générer et vous ne pouvez pas générer deux fois les nombres restants.


Dire simultanément "comment faire pour que le module aléatoire rejoue le numéro s'il a déjà été généré ou appartient à une liste." ET "Donc, fondamentalement, je veux que les nombres de oldNumbers ne soient plus générés" est en effet déroutant et ne va pas de pair. Ce dernier signifie que la boule1, la boule2, la boule3, la boule4 et la boule5 peuvent avoir le même numéro de répétition (à l'exclusion de l'un de ceux des anciens numéros), mais la première citation indique que les cinq variables de balle doivent être différentes et exclure également les anciens numéros. Alors oui, comme je l'ai dit, la question n'était pas claire.