如何生成一个不以0开头并具有唯一数字的随机4位数字?

Men*_* A. 38 python random python-3.x

这工作得很好,但有时候数字从0开始:

import random
numbers = random.sample(range(10), 4)
print(''.join(map(str, numbers)))
Run Code Online (Sandbox Code Playgroud)

我发现了很多例子,但没有一个能保证序列不会以0.

Thi*_*lle 67

我们生成1到9范围内的第一个数字,然后从剩余数​​字中取出接下来的3个数字:

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)))
Run Code Online (Sandbox Code Playgroud)

生成的数字是等概率的,我们只需一步即可获得有效数字.

  • @Claudio生成的数字的独立性是良好的伪随机生成器必须满足的基本属性之一.我认为Python的随机性非常好,以至于后续调用可以被认为是独立的. (12认同)
  • Downvoted,因为这是最热门答案中最慢的.这将set算术与`random.sample`结合起来,两者都很慢. (3认同)
  • 请注意,尽管此方法确实以相同的概率生成每个可能的输出,但这一事实并非显而易见.它确实产生等概率原因的关键原因是,在选择第一个数字之后,无论选择哪个第一个数字,剩余可能数字的数量都是相同的.特别是,如果您试图反转该过程(即首先选择最低的三个不同的数字,然后从剩余的七个数字中选择一个非零的第一个数字),输出将*不是等概率的.(练习读者:为什么?) (2认同)

agh*_*ast 31

只需循环直到你有自己喜欢的东西:

import random

numbers = [0]
while numbers[0] == 0:
    numbers = random.sample(range(10), 4)

print(''.join(map(str, numbers)))
Run Code Online (Sandbox Code Playgroud)

  • @BoundaryImposition和所有其他downvoters:这是一个非常通用的解决方案.它甚至有一个名字,"拒绝抽样".大多数正态分布的实现都使用拒绝采样. (12认同)
  • @Claudio对于所有结果,概率仍然有效,所以我不确定你的意思不是随意的,应该是 (7认同)
  • @Claudio对不起,您应该在建议所有答案都不正确之前咨询关于接受拒绝抽样的某种参考并审查条件概率. (6认同)
  • @BoundaryImposition和所有其他的downvoters:在Austin Hastings,MSeifert,karakfa和Thierry Lathuille的答案中,这是python 2.7和python 3.4中最快的答案.实际上,接受的答案是最慢的,比这个答案慢40%(python 2.7). (3认同)

MSe*_*ert 20

这与其他答案非常相似,但不是sample或者shuffle你可以在1000-9999范围内绘制一个随机整数,直到得到一个只包含唯一数字的整数:

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)
Run Code Online (Sandbox Code Playgroud)

正如@Claudio在评论中指出的那样,范围实际上只需要是1023 - 9876,因为该范围之外的值包含重复的数字.

一般来说random.randint会比快得多random.shufflerandom.choice因此即使它更可能一个需要借鉴多次(如@karakfa指出的),它比任何快达3倍shuffle,choice办法也需要join个位数.

  • 为了使它更加完美,您可以使用例如**random.randint(1023,9876)**进一步限制选择范围,对吗? (6认同)
  • @MSeifert当然,这是4位数.你的拒绝空间会爆炸,并用7位数减慢你的速度(我知道这不是问题:)).实际上,我最喜欢这个答案. (2认同)

tev*_*dar 15

我不太了解Python,但有点像

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
Run Code Online (Sandbox Code Playgroud)

一个更有用的迭代,实际创建一个数字:

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)
Run Code Online (Sandbox Code Playgroud)

在窃取其他解决方案中的碎片后,再加上来自@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)
Run Code Online (Sandbox Code Playgroud)


kar*_*kfa 11

拒绝抽样方法.从10位数创建一个4位数的随机组合,如果与标准不匹配则重新取样.

r4=0    
while r4 < 1000:
    r4=int(''.join(map(str,random.sample(range(10),4))))
Run Code Online (Sandbox Code Playgroud)

注意到这与@Austin Haskings的答案基本相同

  • @BoundaryImposition - 你在这里咆哮错误的树.拒绝采样是一种非常广泛使用的技术.这个答案的唯一问题是Austin Hasking在两分钟前写了一个非常相似的答案(可能是在karakfa写这个答案的时候),Austin Hasking的回答有点好. (7认同)
  • 可能性为零......你会惊讶于这种技术在实践中的常用程度. (3认同)
  • 概率当然不是零. (2认同)
  • 对于所有实际目的,概率可以忽略不计.例如,循环1000次而不产生有效样本(在我的计算机上需要16毫秒)是概率10 ^( - 1000)事件. (2认同)

Foo*_*167 11

[固定]在一个位置上移动所有四位数字不对.固定位置的交换前导零也不对.但是,前导零与九个位置中的任何一个的随机交换是正确的并给出相同的概率:

""" 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])))
Run Code Online (Sandbox Code Playgroud)

  • 但并非所有可能的值都以相同的概率绘制.因为例如`1234`和'01234`产生相同的结果,而包含非前导零的数字(例如'1023`)只有一种可能性被绘制. (3认同)

Jea*_*bre 7

您可以使用3个数字的全范围,然后在剩余数字中选择前导数字:

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)))
Run Code Online (Sandbox Code Playgroud)

另一种方法,如果需要重复选择(如果你对数字位数保持合理),则是使用前导计算可能输出的列表itertools.permutations,过滤掉前导零的那些,并构建整数列表从中:

import itertools,random

l = [int(''.join(map(str,x))) for x in itertools.permutations(range(10),4) if x[0]]
Run Code Online (Sandbox Code Playgroud)

这是一些计算时间,但是之后你可以打电话:

random.choice(l)
Run Code Online (Sandbox Code Playgroud)

你想要多少次.它非常快,并提供均匀分布的随机性.

  • 除了允许的结果不是那么可能; 例如,有两种方法可以获得1230,但只有一种方法可以获得1234. (10认同)
  • 但你不能拥有'0023`.只有一个`0` (4认同)