我正在尝试获得序列的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]
不连续而感到不适。
我在做一些小码打高尔夫球时遇到了这个问题,所以为了兴趣起见,看到一个简单的解决方案和/或一个有效的解决方案也不错,对我现有的代码并不那么感兴趣。
答案 0 :(得分:6)
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。
答案 1 :(得分:1)
许多解决方案都可以针对此问题进行攻击,但如果序列是严格随机的,则必须小心。例如,首先选择0和len(seq)-n*l
之间的随机数并说第一个序列将从那里开始,然后以递归方式工作,这是错误的。
问题相当于随机选择n+1
整数,使其总和等于len(seq)-l*n
。 (这些数字将是序列之间的&#34;间隙和#34;)要解决它,您可以看到this question。
答案 2 :(得分:1)
这在Python 3.3.2中对我有用。它应该向后兼容Python 2.7。
from random import randint as r
def greater_than(n, lis, l):
for element in lis:
if n < element + l:
return False
return True
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)
# Setup
left_to_do = n
tried = []
result = []
# The main loop
while left_to_do > 0:
while True:
index = r(0, len(seq) - 1)
if greater_than(index, tried, l) and index <= len(seq) - left_to_do * l:
tried.append(index)
break
left_to_do -= 1
result.append(seq[index:index+l])
# Done
return result
a = [1, 2, 3, 4, 5, 6]
print(rand_parts(a, 3, 2))
以上代码将始终打印[[1,2],[3,4],[5,6]]
答案 3 :(得分:0)
如果你以递归的方式做到这一点,那就简单多了。从第一部分开始(所以其余部分适合):
[0:total_len - (numer_of_parts - 1) * (len_of_parts)]
然后递归剩下的事情:
rand_parts(seq - begining _to_end_of_part_you_grabbed, n - 1, l)
答案 4 :(得分:0)
首先,我认为您需要澄清术语 random 的含义。
当您对子序列本身设置特定限制时,如何生成真正的随机子序列列表?
据我所知,任何人都可以在这种情况下实现的最佳“随机性”是生成符合条件的所有子序列列表,并从池中选择您需要的多个子序列随机的。
现在根据我几年前所采用的算法类的经验,你的问题似乎是一个典型的例子,可以使用贪心算法来解决这些问题(但是可能?)首先对你实际问的内容做出假设:
假设上面这是一个贪心算法,它在线性时间内生成一个子序列列表(不包括排序,即O(n * log(n))): / p>
def subseq(seq, count, length):
s = sorted(list(set(seq)))
result = []
subseq = []
for n in s:
if len(subseq) == length:
result.append(subseq)
if len(result) == count:
return result
subseq = [n]
elif len(subseq) == 0:
subseq.append(n)
elif subseq[-1] + 1 == n:
subseq.append(n)
elif subseq[-1] + 1 < n:
subseq = [n]
print("Impossible!")
算法的要点如下:
希望这就是你要找的东西。
编辑:出于某种原因,我错误地认为子序列中没有重复的值,这个允许它。
def subseq2(seq, count, length):
s = sorted(seq)
result = []
subseq = []
for n in s:
if len(subseq) == length:
result.append(subseq)
if len(result) == count:
return result
subseq = [n]
elif len(subseq) == 0:
subseq.append(n)
elif subseq[-1] + 1 == n or subseq[-1] == n:
subseq.append(n)
elif subseq[-1] + 1 < n:
subseq = [n]
print("Impossible!")