Say I have a range(1, n + 1)
. I want to get m
unique pairs.
What I found is, if the number of pairs is close to n(n-1)/2
(maxiumum number of pairs), one can't simply generate random pairs everytime because they will start overriding eachother. I'm looking for a somewhat lazy solution, that will be very efficient (in Python's world).
My attempt so far:
def get_input(n, m):
res = str(n) + "\n" + str(m) + "\n"
buffet = range(1, n + 1)
points = set()
while len(points) < m:
x, y = random.sample(buffet, 2)
points.add((x, y)) if x > y else points.add((y, x)) # meeh
for (x, y) in points:
res += "%d %d\n" % (x, y);
return res
答案 0 :(得分:3)
You can use combinations
to generate all pairs and use sample
to choose randomly. Admittedly only lazy in the "not much to type" sense, and not in the use a generator not a list sense :-)
from itertools import combinations
from random import sample
n = 100
sample(list(combinations(range(1,n),2)),5)
If you want to improve performance you can make it lazy by studying this Python random sample with a generator / iterable / iterator
the generator you want to sample from is this: combinations(range(1,n)
答案 1 :(得分:2)
这是一种方法,它采用0 to n*(n-1)/2 - 1
范围内的数字并将其解码为0 to n-1
范围内的一对唯一项。为了方便起见,我使用了基于0的数学,但是如果愿意,您当然可以将1添加到所有返回的对中:
import math
import random
def decode(i):
k = math.floor((1+math.sqrt(1+8*i))/2)
return k,i-k*(k-1)//2
def rand_pair(n):
return decode(random.randrange(n*(n-1)//2))
def rand_pairs(n,m):
return [decode(i) for i in random.sample(range(n*(n-1)//2),m)]
例如:
>>> >>> rand_pairs(5,8)
[(2, 1), (3, 1), (4, 2), (2, 0), (3, 2), (4, 1), (1, 0), (4, 0)]
数学很难轻易解释,但是k
定义中的decode
是通过求解二次方程获得的,该二次方程给出triangular numbers的数量为{{1} },以及<= i
处在三角形数字序列中的位置,告诉您如何从中解码出唯一的一对。关于此解码的有趣之处在于,它根本不使用i
,而是实现了从一组自然数(从0开始)到所有自然对对的一对一的对应关系。
答案 2 :(得分:1)
I don't think any thing on your line can improve. After all, as your m
get closer and closer to the limit n(n-1)/2
, you have thinner and thinner chance to find the unseen pair.
I would suggest to split into two cases: if m
is small, use your random approach. But if m
is large enough, try
pairs = list(itertools.combination(buffet,2))
ponits = random.sample(pairs, m)
Now you have to determine the threshold of m
that determines which code path it should go. You need some math here to find the right trade off.