Cela fonctionne presque bien mais le nombre commence parfois par 0:
import random
numbers = random.sample(range(10), 4)
print(''.join(map(str, numbers)))
J'ai trouvé beaucoup d'exemples mais aucun ne garantit que la séquence ne commencera pas par 0
.
Nous générons le premier chiffre dans la plage 1 - 9, puis prenons les 3 suivants parmi les chiffres restants:
import random
# We create a set of digits: {0, 1, .... 9}
digits = set(range(10))
# We generate a random integer, 1 <= first <= 9
first = random.randint(1, 9)
# We remove it from our set, then take a sample of
# 3 distinct elements from the remaining values
last_3 = random.sample(digits - {first}, 3)
print(str(first) + ''.join(map(str, last_3)))
Les nombres générés sont équiprobables et nous obtenons un nombre valide en une seule étape.
Bouclez jusqu'à ce que vous ayez quelque chose que vous aimez:
import random
numbers = [0]
while numbers[0] == 0:
numbers = random.sample(range(10), 4)
print(''.join(map(str, numbers)))
Ceci est très similaire aux autres réponses mais au lieu de sample
ou shuffle
, vous pouvez dessiner un entier aléatoire dans la plage 1000-9999 jusqu'à ce que vous en obteniez un qui ne contient que des chiffres uniques:
import random
val = 0 # initial value - so the while loop is entered.
while len(set(str(val))) != 4: # check if it's duplicate free
val = random.randint(1000, 9999)
print(val)
Comme @Claudio l'a souligné dans les commentaires, la plage ne doit en fait être que de 1023 à 9876 car les valeurs en dehors de cette plage contiennent des chiffres en double.
Généralement random.randint
sera beaucoup plus rapide que random.shuffle
ou random.choice
donc même s'il est plus probable que l'on doive dessiner plusieurs fois (comme souligné par @karakfa) c'est jusqu'à 3 fois plus rapide que n'importe quelle approche shuffle
, choice
qui doit également join
les chiffres uniques.
Je ne sais pas Python bien, mais quelque chose comme
digits=[1,2,3,4,5,6,7,8,9] <- no zero
random.shuffle(digits)
first=digits[0] <- first digit, obviously will not be zero
digits[0]=0 <- used digit can not occur again, zero can
random.shuffle(digits)
lastthree=digits[0:3] <- last three digits, no repeats, can contain zero, thanks @Dubu
Une itération plus utile, créant en fait un nombre:
digits=[1,2,3,4,5,6,7,8,9] # no zero
random.shuffle(digits)
val=digits[0] # value so far, not zero for sure
digits[0]=0 # used digit can not occur again, zero becomes a valid pick
random.shuffle(digits)
for i in range(0,3):
val=val*10+digits[i] # update value with further digits
print(val)
Après avoir volé des morceaux d'autres solutions, plus appliqué la pointe de @DavidHammen:
val=random.randint(1,9)
digits=[1,2,3,4,5,6,7,8,9]
digits[val-1]=0
for i in random.sample(digits,3):
val=val*10+i
print(val)
méthode d'échantillonnage de rejet. Créez une combinaison aléatoire à 4 chiffres à partir de 10 chiffres et rééchantillonnez si elle ne correspond pas aux critères.
r4=0
while r4 < 1000:
r4=int(''.join(map(str,random.sample(range(10),4))))
a remarqué que c'est essentiellement la même chose que @Austin Haskings réponse
[Fixe] Décaler les quatre chiffres sur une position n'est pas correct. L'échange de zéro de tête avec une position fixe n'est pas non plus correct. Mais l'échange aléatoire du zéro de tête avec l'une des neuf positions est correct et donne une probabilité égale:
""" Solution: randomly shuffle all numbers. If 0 is on the 0th position,
randomly swap it with any of nine positions in the list.
Proof
Lets count probability for 0 to be in position 7. It is equal to probability 1/10
after shuffle, plus probability to be randomly swapped in the 7th position if
0 come to be on the 0th position: (1/10 * 1/9). In total: (1/10 + 1/10 * 1/9).
Lets count probability for 3 to be in position 7. It is equal to probability 1/10
after shuffle, minus probability to be randomly swapped in the 0th position (1/9)
if 0 come to be on the 0th position (1/10) and if 3 come to be on the 7th position
when 0 is on the 0th position (1/9). In total: (1/10 - 1/9 * 1/10 * 1/9).
Total probability of all numbers [0-9] in position 7 is:
9 * (1/10 - 1/9 * 1/10 * 1/9) + (1/10 + 1/10 * 1/9) = 1
Continue to prove in the same way that total probability is equal to
1 for all other positions.
End of proof. """
import random
l = [0,1,2,3,4,5,6,7,8,9]
random.shuffle(l)
if l[0] == 0:
pos = random.choice(range(1, len(l)))
l[0], l[pos] = l[pos], l[0]
print(''.join(map(str, l[0:4])))
Vous pouvez utiliser la gamme complète pour 3 numéros, puis choisissez le numéro de tête parmi les numéros restants:
import random
numbers = random.sample(range(0,10), 3)
first_number = random.choice(list(set(range(1,10))-set(numbers)))
print(''.join(map(str, [first_number]+numbers)))
Une autre façon, si le choix doit être répété (et si vous restez raisonnable sur le nombre de chiffres), est de pré-calculer la liste des sorties possibles en utilisant itertools.permutations
, en filtrant ceux avec un zéro de tête et en construisant une liste d'entiers à partir de celui-ci:
import itertools,random
l = [int(''.join(map(str,x))) for x in itertools.permutations(range(10),4) if x[0]]
C'est un peu de temps de calcul, mais après cela, vous pouvez appeler:
random.choice(l)
autant de fois que vous le souhaitez. C'est très rapide et fournit un aléatoire uniformément réparti.
Je ne sais pas Python donc je vais poster une solution pseudo-code-ish pour ce problème spécifique:
Créez une variable de recherche contenant une liste de chiffres basée sur 0:
lu = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Générez quatre nombres aléatoires basés sur 0 comme suit:
r1 = random number between 0 and 8
r2 = random number between 0 and 8
r3 = random number between 0 and 7
r4 = random number between 0 and 6
Utilisez la variable de recherche pour convertir des nombres aléatoires en chiffres un par un. Après chaque recherche, mutez la variable de recherche en supprimant le chiffre qui a été utilisé:
d1 = lu[r1]
lu.remove(d1)
lu.insert(0)
d2 = lu[r2]
lu.remove(d2)
d3 = lu[r3]
lu.remove(d3)
d4 = lu[r4]
lu.remove(d4)
Imprimez le résultat:
print concatenate(d1, d2, d3, d4)
Il est possible de généraliser un peu cette idée. Par exemple, vous pouvez créer une fonction qui accepte une liste (de chiffres) et un nombre (longueur souhaitée du résultat); la fonction renvoie le numéro et mute la liste en supprimant les chiffres utilisés. Voici une implémentation JavaScript de cette solution:
function randomCombination(list, length) {
var i, Rand, result = "";
for (i = 0; i < length; i++) {
Rand = Math.floor(Math.random() * list.length);
result += list[Rand];
list.splice(Rand, 1);
}
return result;
}
function desiredNumber() {
var list = [1, 2, 3, 4, 5, 6, 7, 8, 9],
result;
result = randomCombination(list, 1);
list.Push(0);
result += randomCombination(list, 3);
return result;
}
var i;
for (i = 0; i < 10; i++) {
console.log(desiredNumber());
}
Voici comment je le ferais
while True:
n = random.randrange(1000, 10000)
if len(set(str(n))) == 4: # unique digits
return n
Plus généralement, étant donné un générateur, vous pouvez utiliser les commandes intégrées filter
et next
pour prendre le premier élément qui satisfait certains tests une fonction.
numbers = iter(lambda: random.randrange(1000, 10000), None) # infinite generator
test = lambda n: len(set(str(n))) == 4
return next(filter(test, numbers))
Avertissement: il s'agit d'une terrible approche anti-Python, strictement pour la partie benchmarking (voir les commentaires de @ DavidHammen, et http://ideone.com/qyopLF ) L'idée est de générer les numéros de séquence de les chiffres en une seule étape, puis corrigez les collisions:
rnd=random.randint(0,4535)
(rnd,d1)=divmod(rnd,9)
(rnd,d2)=divmod(rnd,9)
#(rnd,d3)=divmod(rnd,8)
#(rnd,d4)=divmod(rnd,7)
(d4,d3)=divmod(rnd,8) # miracle found: 1 divmod happens to run faster than 2
Maintenant, nous avons d1 = 0..8, d2 = 0..8, d3 = 0..7, d4 = 0..6, il peut être testé en exécutant l'extrait de code avec rnd = 4535 (4535 = 9 * 9 * 8 * 7-1, soit dit en passant)
Tout d'abord, d1 doit être corrigé
d1=d1+1 # now d1 = 1..9
Alors d2 doit "sauter" d1 si nécessaire
if d2>=d1
d2=d2+1 # now d2 = 0..9 "-" d1
Ensuite, la même chose doit être faite avec les chiffres restants, devenant très vite laid:
if d3>=d1:
d3=d3+1 # now d3 = 0..8 "-" d1
if d3>=d2:
d3=d3+1 # now d3 = 0..9 "-" {d1,d2}
Elif d3>=d2: # this branch prepares for the other variant
d3=d3+1
if d3>=d1: # ">=" is preserved for consistency, here "==" may occur only
d3=d3+1
Et la dernière partie est catastrophique:
if d4>=d1:
d4=d4+1
if d4>=d2:
d4=d4+1
if d4>=d3:
d4=d4+1
Elif d4>=d3:
d4=d4+1
if d4>=d2:
d4=d4+1
Elif d4>=d2:
d4=d4+1
if d4>=d1:
d4=d4+1
if d4>=d3:
d4=d4+1
Elif d4>=d3:
d4=d4+1
if d4>=d1:
d4=d4+1
Elif d4>=d3:
d4=d4+1
if d4>=d2:
d4=d4+1
if d4>=d1:
d4=d4+1
Elif d4>=d1:
d4=d4+1
if d4>=d2:
d4=d4+1
Pour les nombres plus longs, cela pourrait fonctionner plus rapidement avec les champs de bits, mais je ne vois pas de manière triviale. (Vérifier une fois les relations> = ne suffit pas, car la collision peut facilement se produire après avoir effectué une incrémentation. Par exemple, d1 = 1, d2 = 2, d3 = 1: d3 entre en collision avec d1, mais ne se heurte pas initialement à d2. Cependant, après avoir "percé le trou" à 1, d3 devient 2 et maintenant il entre en collision avec d2. Il n'y a aucun moyen trivial de repérer cette collision à l'avance)
Comme le code pue l'enfer, je mets une étape de vérification à la fin
val = d1*1000 + d2*100 + d3*10 + d4
#if len(set(str(val))) != 4: print(str(val)+" "+str(o1)+","+str(o2)+","+str(o3)+","+str(o4))
if len(set(str(val))) != 4: print(val)
Il est déjà plus rapide que les autres codes vraiment rapides (la vérification commentée affiche les chiffres originaux conservés après les divmod-s, à des fins de débogage. Ce n'est pas le genre de code qui fonctionne immédiatement ...). Commenter les deux vérifications le rend encore plus rapide.
EDIT: à propos de vérifier ceci et cela
Il s'agit d'une approche qui maintient une relation 1: 1 entre l'ensemble minimal d'entrées valides (0 ... 4535) et les sorties valides (les 9 * 9 * 8 * 7 nombres possibles à 4 chiffres avec des chiffres distincts, sans commencer par -0). Ainsi, une simple boucle peut et doit générer tous les nombres, ils peuvent être vérifiés un par un et ils peuvent être collectés dans un ensemble par exemple afin de voir s'ils sont tous des résultats distincts
Pratiquement:
collect=set()
for rnd in range(0,4536):
(rnd,d1)=divmod(rnd,9)
... rest of the code, also the verification step kept active ...
collect.add(val)
print(len(collect))
1) Il n'imprimera rien dans la boucle (tous les résultats sont des nombres à 4 chiffres avec des chiffres distincts)
2) Il imprimera 4536 à la fin (tous les résultats sont distincts)
On peut ajouter une vérification pour le premier chiffre (d1), ici et maintenant je suppose simplement que
"(quelque chose de mod 9) +1" ne sera pas 0.
next
Une façon d'écrire en Pythonic serait d'utiliser 2 générateurs imbriqués et next
:
from random import randint
from itertools import count
print(next(i for i in (randint(1023, 9876) for _ in count()) if len(set(str(i))) == 4))
# 8756
Il s'agit essentiellement d'une variante à une ligne de @ MSeifert's answer
Si vous avez besoin de nombreux nombres aléatoires, vous pouvez investir du temps et de la mémoire pour prétraiter tous les nombres acceptables:
import random
possible_numbers = [i for i in range(1023, 9877) if len(set(str(i))) == 4]
1023
et 9877
sont utilisés comme limites car aucun int inférieur à 1023 ou supérieur à 9876 ne peut avoir 4 nombres de distince uniques.
Ensuite, il vous suffirait de random.choice
pour une génération très rapide:
print(random.choice(possible_numbers))
# 7234