我有一个数字列表,表示一行中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)
答案 0 :(得分:1)
我的方法如下:
通过执行适当的算术,计算出结果序列中将出现多少个零。我们将调用此值n
,并调用输入列表k
的长度。
现在,假设我们为一行中的给定结果序列写出n
个零。要创建一个有效的序列,我们需要选择k
个地方,我们将插入适当数量的序列,并且我们有n + 1
个选项,在任何两个数字之间,或者在开头或结束。因此,我们可以使用itertools.combinations
向我们提供所有可能的位置组,要求它选择0到n之间的k
值。
给定一个位置的组合,按升序排列,我们可以计算出在第一组之前出现了多少个零(它是组合中的第一个值),第二个(它是两者之间的差异)当我们迭代时,我们需要在零组之间交替(这些组中的第一个和/或最后一个可能是空的)和一组一组;所以一般来说还有一组零而不是一组零 - 但我们可以通过在末尾添加一个“虚拟”零长度组来清理它。我们还需要从那些位置获得“重叠”的差异;幸运的是there's a trick for this。
这一部分放在一起时很棘手;我将为它编写一个辅助函数,首先:
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_positions
和one_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']