【问题标题】:Splitting up a list into parts of balanced lengths将列表拆分为平衡长度的部分
【发布时间】:2009-09-04 16:04:41
【问题描述】:

我需要一个算法,它给出一个列表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)]

不要问我为什么它有效。 :) 不过,我会给得票最多的那个答案。

【问题讨论】:

  • 如果我的想法正确,您必须事先进行排序。 lst.sort() 有什么问题,然后线性遍历它以挑选元素?无论如何它是 O([the sort func])。
  • @Corey D:这个问题略有不同
  • @voyager:在 Python 中使该算法适应这个问题是一个简单的练习。
  • 平衡是什么意思?如果您试图最小化任何子列表的最大总和,那么有一个应用程序----我的意思是,一个解决方案。如果是这种情况,会挖掘它。

标签: python algorithm


【解决方案1】:

这是我想出的代码,没有排序。如果输入未排序,只需点击 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

【讨论】:

  • 这是一个尽可能简洁的回合。不过,这是一个棘手的问题。
  • 这将是一个有趣的代码高尔夫问题。我仍在修补解决方案。
【解决方案2】:

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

>>> 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]]

【讨论】:

    【解决方案3】:

    如果我理解您的问题...您只需为 mod(n) 下的每个列表添加一项,其中您有 algo (range(a,b), n)

    所以你应该:

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

    【讨论】:

      【解决方案4】:

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

      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)]
      

      【讨论】:

        【解决方案5】:

        聚会有点晚了,但是……

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

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

        【讨论】:

        • 我没有测试过,但如果它有效,那我就完蛋了! :)
        猜你喜欢
        • 1970-01-01
        • 2018-07-18
        • 2011-01-08
        • 2020-10-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多