如何生成一个随机的4位数不是从0开始,并有唯一的数字?

这工作得很好,但有时从0开始。

import random numbers = random.sample(range(10), 4) print(''.join(map(str, numbers))) 

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

我们生成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))) 

生成的数字是等概率的,我们得到一个有效的数字在一个步骤。

循环,直到你有你喜欢的东西:

 import random numbers = [0] while numbers[0] == 0: numbers = random.sample(range(10), 4) print(''.join(map(str, numbers))) 

这与其他答案非常相似,但不是sampleshuffle您可以在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) 

正如@Claudio在注释中指出的,范围实际上只需要是1023 – 9876,因为那个范围之外的值包含重复的数字。

一般来说, random.randint将比random.shufflerandom.choice ,即使更可能需要多次绘制(如@karakfa指出的那样),它比任何shuffle choice方法快3倍需要join个位数。

我不太了解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 

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

 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) 

在从其他解决scheme中偷取件之后,再加上从@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) 

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

 """ 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]))) 

拒收抽样方法。 从10个数字创build一个4位随机组合,如果不符合标准,则重新采样。

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

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

您可以使用全部范围的3个号码,然后select其余号码中的前导号码:

 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))) 

另一种方法是,如果select需要重复(如果对数字位数保持合理的话),则是使用itertools.permutations预先计算可能的输出列表,用前导零来过滤出可能的输出,然后构build一个它的整数列表:

 import itertools,random l = [int(''.join(map(str,x))) for x in itertools.permutations(range(10),4) if x[0]] 

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

 random.choice(l) 

尽可能多的你想要的。 这是非常快速的,并提供一个均匀分布的随机。

我不知道Python,所以我会发布这个特定问题的伪代码解决scheme:

  • 创build一个包含基于0的数字列表的查找variables:

     lu = [1, 2, 3, 4, 5, 6, 7, 8, 9] 
  • 生成四个基于0的随机数,如下所示:

     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 
  • 使用查找variables将随机数字逐个转换为数字。 每次查找后,通过删除已经使用的数字来改变查找variables:

     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) 
  • 打印结果:

     print concatenate(d1, d2, d3, d4) 

有一点可以概括这个想法。 例如,您可以创build一个函数,它接受一个(数字)列表和一个数字(期望的结果长度); 该函数将返回数字并通过移除用完的数字来改变列表。 下面是这个解决scheme的JavaScript实现:

 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()); } 

这是我该怎么做的

 while True: n = random.randrange(1000, 10000) if len(set(str(n))) == 4: # unique digits return n 

更一般地说,给定一个生成器,可以使用内置filternext获取满足某些testing函数的第一个元素。

 numbers = iter(lambda: random.randrange(1000, 10000), None) # infinite generator test = lambda n: len(set(str(n))) == 4 return next(filter(test, numbers)) 

将发电机与next台相结合

Pythonic的写法是使用2个嵌套的生成器, 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 

这基本上是@ MSeifert的答案的单线变体

预处理所有可接受的数字

如果你需要很多随机数,你可以投入一些时间和内存来预处理所有可接受的数字:

 import random possible_numbers = [i for i in range(1023, 9877) if len(set(str(i))) == 4] 

10239877被用作边界,因为没有低于1023的int或高于9876的int可以有4个唯一的distince数字。

那么,你只需要random.choiceselect一个非常快的一代:

 print(random.choice(possible_numbers)) # 7234 

免责声明:这是一个可怕的反Python方法,严格的基准testing部分(请参阅@ DavidHammen的评论, http: //ideone.com/qyopLF)这个想法是生成一个数字的序列号,然后修复任何碰撞:

 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 

现在我们有d1 = 0..8,d2 = 0..8,d3 = 0..7,d4 = 0..6,可以通过运行代码片段rnd = 4535(4535 = 9 * 9 * 8 * 7-1,顺便)

首先,d1必须打补丁

 d1=d1+1 # now d1 = 1..9 

那么如有必要,d2必须“跳过”d1

 if d2>=d1 d2=d2+1 # now d2 = 0..9 "-" d1 

然后,剩下的数字也一样,变得越来越难看:

 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 

最后一部分是灾难性的一个:

 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 

对于更长的数字,它可能会更快的位域,但我没有看到一个微不足道的方法。 (检查> =一次关系是不够的,因为碰撞很容易发生,例如d1 = 1,d2 = 2,d3 = 1:d3碰撞到d1,但是它不会与d2初始冲突。在1处“打洞”之后,d3变为2,现在与d2碰撞,提前发现这个碰撞的方法并不是很简单)

由于代码太臭了,我最后进行了validation

 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) 

它已经比其他真正快速的代码更快了(注释的validation显示了在debugging之后保存的原始数字,这不是立即生效的那种代码)。 评论这两个validation,使其更快。

编辑:关于检查这个和那个

这是一种保持最小有效input(0 … 4535)和有效输出(9 * 9 * 8 * 7可能的4位数字不同的数字,不是以-0)。 因此,一个简单的循环可以并且应该生成所有的数字,它们可以一个接一个地检查,并且可以将它们收集到一个集合中,例如以便查看它们是否都是不同的结果

几乎:

 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)它不会打印循环中的任何内容(所有结果都是4位数字,数字不同)

2)最后打印4536(所有结果都不同)

可以添加validation的第一个数字(D1),现在我只是假设
“(mod 9)+1”不会是0。

这将允许第一个数字后的零 –

 numbers = random.sample(range(1,10),1) + random.sample(range(10),3)