将列表拆分为平衡长度的部分

时间:2009-09-04 16:04:42

标签: python algorithm

我需要一个给出列表L和数字N的算法,返回一个N个较小列表的列表,其中子列表是“平衡的”。例子:

algo(range(1, 8), 3)  -> [[1,2,3], [4,5], [6,7]]
algo(range(1, 6), 4)  -> [[1,2], [3], [4], [5]]
algo(range(1, 12), 5) -> [[1,2,3], [4,5], [6,7], [8,9], [10, 11]]

如您所见,算法应该“更喜欢”输出中的第一个列表。

我已经尝试了几个小时,但我无法找到一个漂亮而简洁的算法。顺便说一句,这将在Python中实现,但它确实是我在此之后的算法。这是作业,这是一个网站,它将在三列(Django)的列表中显示内容。


我从freenode上的#python得到了最好的答案,结果如下:

def split_up(l, n):
    q, r = divmod(len(l), n)
    def division_point(i):
        return i * q + min(i, r)
    return [l[division_point(i):division_point(i+1)] for i in range(n)]

不要问我为什么会这样。 :)尽管如此,我会给出最多票数的答案。

5 个答案:

答案 0 :(得分:5)

这是我提出的代码,没有排序。如果输入没有排序,只需打一个lst.sort()。

我认为这很好,使用迭代器并使用islice来切断下一部分。

import itertools

def partlst(lst, n):
    """Partition @lst in @n balanced parts, in given order"""
    parts, rest = divmod(len(lst), n)
    lstiter = iter(lst)
    for j in xrange(n):
        plen = len(lst)/n + (1 if rest > 0 else 0)
        rest -= 1
        yield list(itertools.islice(lstiter, plen))

parts =  list(partlst(range(1, 15), 5))
print len(parts)
print parts

答案 1 :(得分:1)

假设您希望输出在可能的情况下包含相等长度的列表,否则在开头给出优先级。子列表长度之间的差异不超过一个。

>>> l = [0, 1, 2, 3, 4, 5, 6]
>>> def algo(li, n):
        a, b = divmod(len(li), n)
        c = [a + 1] * b + [a] * (n-b)
        s = 0
        for i, j in enumerate(c):
            c[i] = li[s:s+j]
            s += j
        return c

>>> algo(l, 3)
[[0, 1, 2], [3, 4], [5, 6]]
>>> algo(l, 4)
[[0, 1], [2, 3], [4, 5], [6]]

答案 2 :(得分:0)

如果我理解你的问题......你只需要在mod(n)下为每个列表添加一个项目,你有算法(范围(a,b),n)

所以你应该:

  1. 有b-a> Ñ
  2. 计算b-a = n * x + y(我真的不知道python上是否存在运算符%,所以你应该得到y)
  3. 前y个列表将包含(b-a / n + 1)个元素,其他列表将具有(b-a / n)

答案 3 :(得分:0)

这是对功能性爱好者的致敬:

def algo(l, n):
    if n == 1: return [l]
    q, r = divmod(len(l),n)
    if r: q += 1
    return [l[:q]] + algo(l[q:], n - 1)

这个有点小:

def algo(l, n):
    k = l[:]
    q, r = divmod(len(l),n)
    return [[k.pop(0) for _ in [0] * m]
            for m in [q + 1] * r + [q] * (n - r)]

答案 4 :(得分:0)

有点迟到了,但是......

def algo(l, n):
  return [l[-(-len(l)*i//n):-(-len(l)*(i+1)//n)] for i in range(n)]

在旧版本的Python中使用/而不是//。