每个长度为N个随机,连续和非重叠的子序列

时间:2013-09-05 16:15:34

标签: python list random

我正在尝试获得序列的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]不连续而感到不适。

我在做一些小码打高尔夫球时遇到了这个问题,所以为了兴趣起见,看到一个简单的解决方案和/或一个有效的解决方案也不错,对我现有的代码并不那么感兴趣。

5 个答案:

答案 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 的含义。

当您对子序列本身设置特定限制时,如何生成真正的随机子序列列表?

据我所知,任何人都可以在这种情况下实现的最佳“随机性”是生成符合条件的所有子序列列表,并从池中选择您需要的多个子序列随机的。

现在根据我几年前所采用的算法类的经验,你的问题似乎是一个典型的例子,可以使用贪心算法来解决这些问题(但是可能?)首先对你实际问的内容做出假设:

  • random 实际上意味着应该随机生成一个子序列表(这与我之前说过的有点矛盾),但是可以生成的任何解决方案与其他解决方案一样有效(例如,6个解决方案中的任何一个都可以从输入[1,2,3,4,5,6]中有效,并且你不会关心哪一个)
  • 重申上述内容,您只需要可以生成的任何一个可能的解决方案,并且您需要一个可以输出一个这些有效答案的算法。< / LI>

假设上面这是一个贪心算法,它在线性时间内生成一个子序列列表(不包括排序,即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!") 

算法的要点如下:

  • 您的一个要求是不能有任何重叠,这最终意味着您需要处理唯一数字和唯一数字。所以我使用set()操作来删除所有重复项。然后我对它进行排序。
  • 休息很简单。我只是遍历排序列表并贪婪地形成子序列。
  • 如果算法无法形成足够数量的子序列,则打印“不可能!”

希望这就是你要找的东西。

编辑:出于某种原因,我错误地认为子序列中没有重复的值,这个允许它。

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!")
相关问题