生成n个正整数,其范围内总和为总数的python代码

2024-09-27 09:33:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我也看到过其他帖子在讨论类似的问题。我知道如何生成N个正整数。我还知道如何限制随机生成的整数的和。只满足不在指定值范围内的问题。在

例如,generate_ints(n, total, low, high)应该生成n个值数组,这样每个值都在低值和高值之间,并且总和等于总和。如有任何建议/帮助,我们将不胜感激。在

例如,generate_ints(4, 40, 4, 15)应该生成类似

[7,10,13,10]

我不在乎这些数字是否重复,只要它们不是高度扭曲的。我使用np.randon.randint(5,15,n)来选择整数。在

到目前为止,我已经尝试了以下方法,但是没有用-

^{pr2}$

再次感谢。在


Tags: 数字整数数组建议generate帖子lowtotal
3条回答

如果我正确理解规范,您希望随机生成受限整数compositions,这样每个可能的组合都有相同的被选择的可能性。在

我们可以将this answer应用于均匀生成随机整数partition的问题,从而精确地解决小输入值问题。我们只需要一种方法来计算受限制的k-组成。在数学的this answer中,有一个递归公式可以用来解决一个相关的问题,但事实证明,作为this answer的一部分,有一个更明确的公式,它使用二项式系数。下面是一个纯Python实现:

import functools
import random

@functools.lru_cache(1 << 10)
def C1(n, k, a, b):
    "Counts the compositions of `n` into `k` parts bounded by `a` and `b`" 
    return C2(n - k*(a - 1), k, b - (a - 1))

def C2(n, k, b):
    "Computes C(n, k, 1, b) using binomial coefficients"
    total = 0
    sign = +1

    for i in range(0, k + 1):
        total += sign * choose(k, i) * choose(n - i*b - 1, k - 1)
        sign = -sign

    return total

def choose(n, k):
    "Computes the binomial coefficient of (n, k)"
    if k < 0 or k > n:
        return 0

    if k == 0 or k == n:
        return 1

    k = min(k, n - k)
    c = 1

    for i in range(k):
        c = c * (n - i) // (i + 1)

    return c

def check_pre_and_post_conditions(f):
    def wrapper(n, k, a, b):
        assert 1 <= k <= n, (n, k)
        assert 1 <= a <= b <= n, (n, a, b)
        assert k*a <= n <= k*b, (n, k, a, b)

        comp = f(n, k, a, b)

        assert len(comp) == k, (len(comp), k, comp)
        assert sum(comp) == n, (sum(comp), n, comp)
        assert all(a <= x <= b for x in comp), (a, b, comp)

        return comp
    return functools.wraps(f)(wrapper)

@check_pre_and_post_conditions
def random_restricted_composition(n, k, a, b):
    "Produces a random composition of `n` into `k` parts bounded by `a` and `b`"
    total = C1(n, k, a, b)
    which = random.randrange(total)
    comp = []

    while k:
        for x in range(a, min(b, n) + 1):
            count = C1(n - x, k - 1, a, b)

            if count > which:
                break

            which -= count

        comp.append(x)
        n -= x
        k -= 1

    return comp

要选择一个随机组合,我们只需生成一个比可能的组合总数小的随机索引,然后构造i-th字典组合(有关使用的递归关系的解释,请参阅相关问题)。这应该以同样的概率产生所有可能的结果。在

但是,因为C1(n, k, a, b)是指数增长的,对于n和{}的大值,这种方法相当慢。对于较大的值,近似的解决方案会更好地为您服务。在

import numpy as np

def sampler(samples, sum_to , range_list):
    assert range_list[0]<range_list[1], "Range should be a list, the first element of which is smaller than the second"
    arr = np.random.rand(samples)
    sum_arr = sum(arr)

    new_arr = np.array([int((item/sum_arr)*sum_to) if (int((item/sum_arr)*sum_to)>range_list[0]and int((item/sum_arr)*sum_to)<range_list[1]) \
                            else np.random.choice(range(range_list[0],range_list[1]+1)) for item in arr])
    difference = sum(new_arr) - sum_to
    while difference != 0:
        if difference < 0 :
                for idx in np.random.choice(range(len(new_arr)),abs(difference)):
                    if new_arr[idx] != range_list[1] :
                        new_arr[idx] +=  1

        if difference > 0:
                for idx in np.random.choice(range(len(new_arr)), abs(difference)):
                    if new_arr[idx] != 0 and new_arr[idx] != range_list[0] :
                        new_arr[idx] -= 1
        difference = sum(new_arr) - sum_to
    return new_arr

new_arr = sampler (2872,30000,[5,15])
print "Generated random array is :"
print new_arr
print "Length of array:", len(new_arr)
print "Max of array: ", max(new_arr)
print "min of array: ", min(new_arr)
print "and it sums up to %d" %sum(new_arr)

结果:

^{pr2}$

这是我的尝试,我会解释的。在

import numpy as np


def generate_ints(n, total, low, high):
    begin = 0
    randys = []
    correctTotal = False
    while correctTotal is False:
        while begin < n:
            r1 = np.random.randint(low, high, 1)
            randys.append(r1)
            begin += 1
        if sum(randys) == total:
            correctTotal = True
        else:
            begin = 0
            del randys[:]
    generated_list = np.array(randys).tolist()
    gen = [g[0] for g in generated_list]
    return gen


my_list = generate_ints(4, 40, 4, 15)
print "Generated list '{}' with sum {}.".format(my_list, sum(my_list))

在函数内部,我设置了两个常量,randys和{}。在内部while循环中,只要begin小于n,它就会在lowhigh之间生成{}随机整数。如果和等于total,则退出外部while循环,否则需要重置常量。

只返回randys将给出一个NumPy array的列表。使用tolist()方法,将生成一个列表。

现在我们有一个列表列表。我用了一个简短而甜蜜的清单理解法把它压平了。最后return列出并输出所需的内容。

h。在

相关问题 更多 >

    热门问题