将数字分成随机数量的随机元素?

6
如果我需要将7分成随机数量的随机大小元素,我该怎么做?
这样有时我会得到[3,4],有时会得到[2,3,1],有时会得到[2,2,1,1,0,1]?
我想这很简单,但我似乎无法得到结果。这是我正在尝试的代码(不起作用):
def split_big_num(num):
    partition = randint(1,int(4))
    piece = randint(1,int(num))
    result = []
    for i in range(partition):
        element = num-piece
        result.append(element)
        piece = randint(0,element)
#What's next?
        if num - piece == 0:
            return result
    return result

编辑:每个结果数字都应小于初始数字,并且零的数量不应少于分区数。


请说明您所说的随机元素数量是什么意思。您是指每个子集长度被选中的概率相同吗?还是您是指每个子集被选中的概率相同?这两者意义完全不同。 - David Robinson
2
它是否会返回[7]?那么[0,0,0,0,0,7]呢?它们可能吗? - DanRedux
抱歉,我必须澄清一下,不,没有7。 - Stpn
2
你能有多少个零是有限制的吗? - Akavall
尝试使用排列和组合的概念,以获取所有可能的组合。 - Ashwini Chaudhary
显示剩余2条评论
4个回答

13

我会选择接下来的这个:

>>> def decomposition(i):
        while i > 0:
            n = random.randint(1, i)
            yield n
            i -= n

>>> list(decomposition(7))
[2, 4, 1]
>>> list(decomposition(7))
[2, 1, 3, 1]
>>> list(decomposition(7))
[3, 1, 3]
>>> list(decomposition(7))
[6, 1]
>>> list(decomposition(7))
[5, 1, 1]

不过,我不确定这个随机分布是否完全均匀。


太好了!非常感谢!一旦SO允许,我将接受这个答案。 - Stpn
好的回答!小问题:使用 n = rn.randint(0, i) 将允许 Stpn 获取零。 - Akavall
@Akavall:还要允许它开始累积很多个0。 - Gareth Latty
这违反了要求,因为它允许返回7。 - ninjagecko
1
好的,我误读了那部分内容,但他的例子中确实有一个零,但处理这个问题可能只是细节。 - Akavall
6
这个分布离完全均匀非常远,你往往会有太多的大数字,并且它们往往出现在开头。 - btilly

4
您需要定义您所说的“随机”。如果您想要一个任意的整数分区,您可以生成所有整数分区,并使用 random.choice。请参见python:生成整数分区。这将在0时不提供结果。如果您允许0,则必须允许具有潜在无限数量的0的结果。
或者,如果您只想随机地取出一些块,请执行此操作:
def arbitraryPartitionLessThan(n):
    """Returns an arbitrary non-random partition where no number is >=n"""
    while n>0:
        x = random.randrange(1,n) if n!=1 else 1
        yield x
        n -= x

由于问题限制,每个数字都应小于原始数字,这使得问题有些棘手;如果允许使用原始数字,则会更加优雅。如果想要 0,请使用 randrange(n),但除非您有没有分享的隐藏原因,否则这样做没有意义。
针对问题编辑的回答:由于您希望“零的数量不应少于分区数”,您可以任意添加 0 到末尾。
def potentiallyInfiniteCopies(x):
    while random.random()<0.5:
        yield x

x = list(arbitraryPartitionLessThan(n))
x += [0]*len(x) + list(potentiallyInfiniteCopies(0))

这个问题相当主观,我强烈建议你选择这个作为你的答案:
def arbitraryPartition(n):
    """Returns an arbitrary non-random partition"""
    while n>0:
        x = random.randrange(1,n+1)
        yield x
        n -= x

组合数的数量增长非常快。因此,即使是一个适度的n值也可能会耗尽您所有的内存。 - btilly

1

递归来拯救:

import random

def splitnum(num, lst=[]):
    if num == 0:
        return lst
    n = random.randint(0, num)
    return splitnum(num - n, lst + [n])

for i in range(10):
    print splitnum(7)

结果:

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

@AshwiniChaudhary:计算返回该序列的可能性,然后你就有答案了。 - Wooble

0

这个解决方案不会插入0(我不理解你对零的规则描述是什么),并且生成除原始数字本身以外的每种可能组合的概率相等。

def split (n):
    answer = [1]
    for i in range(n - 1):
        if random.random() < 0.5:
            answer[-1] += 1
        else:
            answer.append(1)

    if answer == [n]:
        return split(n)
    else:
        return answer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接