在Python中生成特定的位序列

时间:2014-10-15 14:08:53

标签: python permutation

我有一个数字列表,表示一行中1的数量,我有一个整数表示整个序列的长度。所以例如,如果我得到列表[1,2,3]和长度8,那么唯一可能的位序列是10110111.但是如果长度是9,我应该得到 010110111,100110111,101100111和101101110.我想知道是否有一种简单的pythonic方式。我目前的方法是

def genSeq(seq, length):
    strSeq = [str(i) for i in seq]
    strRep = strSeq + ["x" for i in xrange(length-sum(seq))]

    perm = list(set(permutations(strRep)))
    legalSeq = [seq for seq in perm if isLegal(seq) and [char for char in seq if char.isdigit()] == strSeq]
    return [''.join(["1"*int(i) if i.isdigit() else "0" for i in seq]) for seq in legalSeq]


def isLegal(seq):
    for i in xrange(len(seq)-1):
        if seq[i].isdigit() and seq[i+1].isdigit(): return False
    return True

print genSeq([1, 2, 3], 9)

1 个答案:

答案 0 :(得分:1)

我的方法如下:

  1. 通过执行适当的算术,计算出结果序列中将出现多少个零。我们将调用此值n,并调用输入列表k的长度。

  2. 现在,假设我们为一行中的给定结果序列写出n个零。要创建一个有效的序列,我们需要选择k个地方,我们将插入适当数量的序列,并且我们有n + 1个选项,在任何两个数字之间,或者在开头结束。因此,我们可以使用itertools.combinations向我们提供所有可能的位置组,要求它选择0到n之间的k值。

  3. 给定一个位置的组合,按升序排列,我们可以计算出在第一组之前出现了多少个零(它是组合中的第一个值),第二个(它是两者之间的差异)当我们迭代时,我们需要在零组之间交替(这些组中的第一个和/或最后一个可能是空的)和一组一组;所以一般来说还有一组零而不是一组零 - 但我们可以通过在末尾添加一个“虚拟”零长度组来清理它。我们还需要从那些位置获得“重叠”的差异;幸运的是there's a trick for this

  4. 这一部分放在一起时很棘手;我将为它编写一个辅助函数,首先:

    def make_sequence(one_positions, zero_count, one_group_sizes):
        zero_group_sizes = [
            end - begin
            for begin, end in zip((0,) + one_positions, one_positions + (zero_count,))
        ]
        return ''.join(
            '0' * z + '1' * o
            for z, o in zip(zero_group_sizes, one_group_sizes + [0])
        )
    

    现在我们可以回到所有可能序列的迭代:

    def generate_sequences(one_group_sizes, length):
        zero_count = length - sum(one_group_sizes)
        for one_positions in itertools.combinations(
            range(zero_count + 1), len(one_group_sizes)
        ):
            yield make_sequence(one_positions, zero_count, one_group_sizes)
    

    我们当然可以将其折叠回单一功能,但也许你会同意我的意见,最好将这些聪明的东西保存在更易于管理的部分中:)

    这比我想要的更脆弱 - one_positionsone_group_sizes序列需要“填充”以使事情有效,而这又需要假设它们的类型。 one_positions将是一个元组,因为这是itertools.combinations产生的,但我已经硬编码了用户提供的one_group_sizes将成为列表的假设。有办法解决这个问题,但我现在有点筋疲力尽了:)

    无论如何,测试:

    >>> list(generate_sequences([1,2,3], 9))
    ['101101110', '101100111', '100110111', '010110111']
    
    >>> list(generate_sequences([1,1,1], 9))
    ['101010000', '101001000', '101000100', '101000010', '101000001', '100101000', '
    100100100', '100100010', '100100001', '100010100', '100010010', '100010001', '10
    0001010', '100001001', '100000101', '010101000', '010100100', '010100010', '0101
    00001', '010010100', '010010010', '010010001', '010001010', '010001001', '010000
    101', '001010100', '001010010', '001010001', '001001010', '001001001', '00100010
    1', '000101010', '000101001', '000100101', '000010101']