我正在尝试获得序列的n个随机且不重叠的切片,其中每个子序列的长度均为l,最好按出现的顺序排列。
这是我到目前为止的代码,每次尝试使其工作都变得越来越混乱,不用说它行不通。
def rand_parts(seq, n, l):
"""
return n random non-overlapping partitions each of length l.
If n * l > len(seq) raise error.
"""
if n * l > len(seq):
raise Exception('length of seq too short for given n, l arguments')
if not isinstance(seq, list):
seq = list(seq)
gaps = [0] * (n + 1)
for g in xrange(len(seq) - (n * l)):
gaps[random.randint(0, len(gaps) - 1)] += 1
result = []
for i, g in enumerate(gaps):
x = g + (i * l)
result.append(seq[x:x+l])
if i < len(gaps) - 1:
gaps[i] += x
return result
例如,如果我们说
rand_parts([1, 2, 3, 4, 5, 6], 2, 2)
,则可能从下图返回6种可能的结果:[1, 2, 3, 4, 5, 6]
____ ____
[1, 2, 3, 4, 5, 6]
____ ____
[1, 2, 3, 4, 5, 6]
____ ____
[1, 2, 3, 4, 5, 6]
____ ____
[1, 2, 3, 4, 5, 6]
____ ____
[1, 2, 3, 4, 5, 6]
____ ____
因此
[[3, 4], [5, 6]]
是可以接受的,但[[3, 4], [4, 5]]
不能,因为它是重叠的,而[[2, 4], [5, 6]]
也不是,因为[2, 4]
不是连续的。我在进行一些代码打高尔夫球时遇到了这个问题,因此出于兴趣的考虑,同时看到一个简单的解决方案和/或一个有效的解决方案(对我现有的代码不太感兴趣)也将是一件很不错的事情。
最佳答案
def rand_parts(seq, n, l):
indices = xrange(len(seq) - (l - 1) * n)
result = []
offset = 0
for i in sorted(random.sample(indices, n)):
i += offset
result.append(seq[i:i+l])
offset += l - 1
return result
要了解这一点,请首先考虑大小写
l == 1
。然后,基本上只是按排序顺序返回输入数据的random.sample()
;在这种情况下,offset
变量始终为0。l > 1
是前一种情况的扩展。我们使用random.sample()
来获取位置,但是使用offset
来转移连续的结果:这样,我们确保它们是不重叠的范围---即它们的起始距离至少为l
而不是1。