【问题标题】:Python Get Random Unique N PairsPython 获取随机唯一 N 对
【发布时间】:2019-08-10 03:56:24
【问题描述】:

假设我有一个range(1, n + 1)。我想得到m 唯一的对。

我发现,如果对数接近n(n-1)/2(最大对数),则不能每次都简单地生成随机对,因为它们会开始相互覆盖。我正在寻找一个有点懒惰的解决方案,这将非常有效(在 Python 的世界中)。

到目前为止我的尝试:

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

【问题讨论】:

    标签: python algorithm math graph combinations


    【解决方案1】:

    您可以使用combinations 生成所有对,并使用sample 随机选择。诚然,只是在“打字不多”的意义上懒惰,而不是在使用生成器而不是列表意义上:-)

    from itertools import combinations
    from random import sample
    
    n = 100
    sample(list(combinations(range(1,n),2)),5)
    

    如果你想提高性能,你可以通过研究这个来让它变得懒惰 Python random sample with a generator / iterable / iterator

    您要从中采样的生成器是:combinations(range(1,n)

    【讨论】:

      【解决方案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)]
      

      数学很难解释,但decode 的定义中的k 是通过求解一个二次方程得到的三角形数字序列中告诉您如何从中解码出唯一的一对。这个解码的有趣之处在于它根本不使用n,而是实现了从自然数集合(从0开始)到所有自然数对的集合的一一对应。

      【讨论】:

      • 有更全面解释的链接吗?谢谢。
      • 顺便说一句,这是完美的。
      • @AfonsoMatos 我不知道链接。我从枚举(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3) 开始(如果它不依赖于n,这是你需要的那种枚举)注意到有 1 以 1 开头,2 以 2 开头,等等。要获得来自i 的配对,我需要知道i 在哪个“块”中。i = 7,例如在 4 块中 因为 1+2+3 &lt;= 7 &lt; 1+2+3+4 转换为3(3-1)/2 &lt;= 7 &lt; 4(4-1)/2 如果你解决7 = k(k-1)/2 并转为一个整数,你得到k。再多一点代数就能得到另一个索引。
      【解决方案3】:

      我认为您的产品线中没有任何东西可以改进。毕竟,随着您的m 越来越接近极限n(n-1)/2,您找到看不见的配对的机会越来越少。

      我建议分成两种情况:如果m 很小,请使用随机方法。但是如果m足够大,试试

       pairs = list(itertools.combination(buffet,2))
       ponits = random.sample(pairs, m)
      

      现在您必须确定m 的阈值,它决定了它应该走的代码路径。您需要在这里进行一些数学运算才能找到正确的折衷方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-01
        • 2021-06-04
        • 2021-10-11
        • 1970-01-01
        • 2020-12-05
        • 2014-09-13
        • 1970-01-01
        相关资源
        最近更新 更多