用规则随机生成列表元素

时间:2015-07-31 03:36:49

标签: python algorithm

让列表 l n 元素组成,其中

  1. 每个元素应为0或小于或等于 r 的正整数,并且
  2. 列表总和应等于 m
  3. 示例:

    Given n = 5, r = 4, m = 10
    
    l = [4, 3, 2, 0, 1]
    

    很容易实现规则(1),但我想知道是否有任何好主意/算法来实现这两个规则?

4 个答案:

答案 0 :(得分:0)

合理的解释是(i)查找并统计满足规则的所有唯一清单; (ii)以相同的概率随机选择其中一个列表。这种方法的问题在于编码列表列表很复杂。

更简单的方法(更少的代码)是将每个正确的列表暴露给被挑选的相同概率。该算法是:

  1. 检查m<=nr 如果没有,请返回“无”或引发错误。
  2. 循环:在[0,r]中重复生成包含随机数的列表。 打破循环,返回第一个总和列表。
  3. 注意:此处对较少代码的权衡可能会延长执行时间。如果r很大,或者m是不可能的总和,这可能需要一段时间。我们可以通过检查答案只能是零或r-1的限制来缓解这一点。

    from numpy.random import randint
    
    def known_sum_random_list(size,limitint,knownsum):
        if knownsum>size*(limitint-1):
            return None
        if knownsum==size*(limitint-1):
            return size*[limitint-1]
        s=0
        l = size*[0]
        while (s!=knownsum):
            l = randint(0,limitint,size)
            s = sum(l)
        return l
    
    for t in xrange(10):
        print known_sum_random_list(5,4,10)
    

    输出:

    [3 2 1 2 2]
    [1 1 2 3 3]
    [3 0 3 1 3]
    [3 2 0 3 2]
    [2 2 0 3 3]
    [1 3 2 3 1]
    [3 3 0 3 1]
    [2 0 2 3 3]
    [3 1 2 3 1]
    [3 2 0 3 2]
    

答案 1 :(得分:0)

这是一个简单的蛮力解决方案。基本上,您希望生成小于r的随机整数的样本。不符合标准的样本(总和为m)将被拒绝。

import numpy as np

def rand_with_rules(n, r, m):
    if n*(r-1) < m:
        raise ValueError
    while True:
        l = np.random.randint(0, r, size=(n))
        if l.sum() == m:
            return l

请注意,拒绝样本必然会使您的“随机”数字产生偏差。由于你的限制,你不能拥有一套纯粹的随机性,而某些人往往会过度或不足。

例如,情况n,r,m = 2,3,4。符合此标准的唯一系列是(2,2),因此绘制2的可能性为100%,其他为0%值。

从本质上讲,这个解决方案表明你没有先验知道哪些整数最有可能。但是,通过约束,你对数字的后验知识几乎不会真正统一。

对于给定此约束的整数分布,可能有一个聪明的分析解决方案,您可以使用它来生成样本。但我不知道它是什么!

答案 2 :(得分:0)

如果没有验证可以立即满足所有规则,我建议遵循解决方案

import random

def dis(n,m,r):
  l = [0] * n

  for inc in range(1,m):
    l.sort()
    for ind_less_r, less_r in enumerate(l):
      if less_r > r:
          break
    l[random.randint(0,ind_less_r-1)] += 1

  random.shuffle(l)
  return l


for i in range(1,10):
  print dis(10,50,9)

结果是

[7, 7, 6, 1, 6, 3, 5, 4, 4, 6]
[5, 6, 7, 5, 4, 7, 4, 4, 4, 3]
[4, 3, 2, 4, 7, 7, 5, 7, 5, 5]
[4, 4, 5, 6, 4, 6, 6, 4, 5, 5]
[6, 6, 4, 6, 5, 6, 2, 5, 4, 5]
[2, 8, 4, 2, 6, 5, 4, 4, 6, 8]
[6, 6, 3, 4, 5, 5, 5, 5, 6, 4]
[6, 4, 5, 6, 7, 3, 1, 5, 6, 6]
[4, 5, 4, 7, 6, 6, 3, 2, 6, 6]

答案 3 :(得分:0)

由于您在评论中回复说它可以有很多0并且数字可以重复,我推断它不一定是随机的。考虑到这一点,这是一个没有任何循环或包含的基本解决方案。它假定nrm具有有效的值和类型。但是这样的检查很简单,我可以根据要求进行编辑。

def create_list(n, r, m):
    output = [r] * (m/r)
    remainder = m - r * len(output)
    if remainder != 0:
        output += [m - r * len(output)]
    output += [0] * (n - len(output))
    return output

output = create_list(5, 4, 10) # gives [4, 4, 2, 0, 0]
output = create_list(5, 2, 10) # gives [2, 2, 2, 2, 2]

P.S。 - 请求的值小于r,但示例显示的值等于r,所以这是通过示例