如何在range(n, m)
中生成两个随机整数,其中n
和m
相差至少k
(即abs(n-m) >= k
)?我可以想到两个解决方案(它们在下面),但第一个解决方案可能变得不切实际,大k
个,而第二个解决方案偏向于n
或{{1等于m
或lower
。
upper-1
答案 0 :(得分:3)
我们可以使用一点数学来使解决方案更简单。如果我们要求从a, b
中选择随机数range(m, n)
,abs(b-a) >= k
,则我们知道a
必须位于range(m, n-k)
且b
必须在range(m+k,n)
。
因此,我们首先选择a
,然后从符合条件的可用选项子集中选择b:
a = random.randint(m, n-k)
b = random.randint(a+k, n)
请注意,上述答案并未对所有可能的a,b组合进行同等抽样
这是一个改进的解决方案,它将对所有组合赋予相同的权重:
while(True):
a = random.randint(m,n-k)
b = random.randint(m+k,n)
if abs(b-a) >= k:
break
答案 1 :(得分:1)
def randiff_sample(lower, upper, min_diff):
if upper - lower < min_diff:
raise ValueError("upper - lower should be larger than the minimum required difference")
a = random.randint(lower, upper-min_diff -1)
b = random.randint(a+min_diff, upper)
return a,b
答案 2 :(得分:1)
通过选择一个随机整数并应用一些算术,可以获得合适的对。
使用lower = 0
,upper = 10
和min_diff = 5
,可能的对是:
[(0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 6), (1, 7), (1, 8), (1, 9), (2, 7), (2, 8), (2, 9), (3, 8), (3, 9), (4, 9)]
它们形成三角形:
这意味着计算number of possible pairs很容易。也可以使用"Cantor pairing function"为这些对中的每一对分配一个数字。
此功能可以颠倒:从随机整数z
开始,可以获得(x,y)
对。
将这些全部放在一起,代码变为:
from math import floor, sqrt
from random import randrange
def reverse_cantor(z):
w = int(floor((sqrt(8 * z + 1) - 1) / 2)) # see https://en.wikipedia.org/wiki/Pairing_function#Inverting_the_Cantor_pairing_function
t = (w**2 + w) // 2
y = z - t
x = w - y
return (x, y)
def pick_random(lower, upper, min_diff):
height = upper - lower - min_diff
count = height * (height + 1) // 2
z = randrange(0, count)
x, y = reverse_cantor(z)
a = lower + x
b = upper - 1 - y
return (a, b)
通过创建150000个随机对来检查分布是否正确:
from collections import Counter
dist = Counter(pick_random(0, 10, 5) for _ in range(150000))
import matplotlib.pyplot as plt
import numpy as np
labels, values = zip(*sorted(dist.items()))
indexes = np.arange(len(labels))
width = 1
plt.bar(indexes, values, width)
plt.xticks(indexes, labels)
plt.show()
每一对都非常接近出现10000次。
答案 3 :(得分:0)
def get_random(lower, upper, k):
num1 = random.randint(lower, upper)
try:
if upper - num1 < k:
num2 = random.randint(lower, num1 - k)
else:
num2 = random.choice([random.randint(num1 + k, upper), random.randint(lower, num1 - k)])
except ValueError:
return get_random(lower, upper, k)
return num1, num2
这是我的解决方案。
答案 4 :(得分:0)
在这种情况下,更好的解决方案取决于您所寻找的差异的大小。如果范围很宽并且您期望的差异很小,则可以轻松实现。在下面的解决方案中,我已将范围差异除以所需的限制。
import random
def randomGen(upper, lower, min_diff):
if (upper - lower) <= min_diff:
raise ValueError ('Not possible to calculate')
else:
print ((upper - lower) // min_diff)
if (upper - lower) // min_diff >= 1:
x = random.randint(lower, int((-(min_diff/2) + (lower + upper)/2)))
y = random.randint(int(((lower + upper)/2) + min_diff/2), upper )
print (x,y)
min_diff = 200
upper = 480
lower = 279
randomGen(upper, lower, min_diff)