此问题已经在这里有了答案:
我正在寻找一种快速,干净,pythonic的方法将列表分为正好n个几乎相等的分区。
partition([1,2,3,4,5],5)->[[1],[2],[3],[4],[5]]
partition([1,2,3,4,5],2)->[[1,2],[3,4,5]] (or [[1,2,3],[4,5]])
partition([1,2,3,4,5],3)->[[1,2],[3,4],[5]] (there are other ways to slice this one too)
这里Iteration over list slices中有几个答案与我想要的非常接近,除了它们集中在列表的[[size上,我关心列表的[[number(有些他们也垫无)。显然,这些都是微不足道的转换,但是我正在寻找最佳实践。
类似地,人们在How do you split a list into evenly sized chunks?上指出了解决非常相似问题的好方法,但是我对分区的数量比对特定大小更感兴趣,只要它在1之内即可。但我正在寻找最佳实践。def partition(lst, n):
division = len(lst) / n
return [lst[round(division * i):round(division * (i + 1))] for i in range(n)]
def partition(lst, n):
q, r = divmod(len(lst), n)
indices = [q*i + min(i, r) for i in xrange(n+1)]
return [lst[indices[i]:indices[i+1]] for i in xrange(n)]
它还避免使用浮点运算,因为这总是让我感到不舒服。 :)
编辑:一个例子,只是为了与丹尼尔·斯图茨巴赫的解决方案进行对比
>>> print [len(x) for x in partition(range(105), 10)] [11, 11, 11, 11, 11, 10, 10, 10, 10, 10]
def partition ( lst, n ):
return [ lst[i::n] for i in xrange(n) ]
这满足@Daniel Stutzbach的示例中提到的示例:
partition(range(105),10)
# [[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
# [1, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101],
# [2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102],
# [3, 13, 23, 33, 43, 53, 63, 73, 83, 93, 103],
# [4, 14, 24, 34, 44, 54, 64, 74, 84, 94, 104],
# [5, 15, 25, 35, 45, 55, 65, 75, 85, 95],
# [6, 16, 26, 36, 46, 56, 66, 76, 86, 96],
# [7, 17, 27, 37, 47, 57, 67, 77, 87, 97],
# [8, 18, 28, 38, 48, 58, 68, 78, 88, 98],
# [9, 19, 29, 39, 49, 59, 69, 79, 89, 99]]
def partition(lst, n):
increment = len(lst) / float(n)
last = 0
i = 1
results = []
while last < len(lst):
idx = int(round(increment * i))
results.append(lst[last:idx])
last = idx
i += 1
return results
如果len(lst)不能被n均分,则此版本将以大致相等的间隔分配额外的项。例如:
>>> print [len(x) for x in partition(range(105), 10)]
[11, 10, 11, 10, 11, 10, 11, 10, 11, 10]
如果您不介意所有11的开头或结尾,则代码可能会更简单。
n件长度来工作
[[1,max_ratio),将它们彼此依次放置以形成“断坚持'在'断点'之间的正确距离,但错误总长度。将折断的棍子缩放到所需的长度可以使我们我们想要的断点的大概位置。得到整数断点需要随后的舍入。
[不幸的是,四舍五入可以使片段太短,并让您超过max_ratio。请参阅此答案的底部以获取例如。import random
def splitting_points(length, n, max_ratio):
"""n+1 slice points [0, ..., length] for n random-sized slices.
max_ratio is the largest allowable ratio between the largest and the
smallest part.
"""
ratios = [random.uniform(1, max_ratio) for _ in range(n)]
normalized_ratios = [r / sum(ratios) for r in ratios]
cumulative_ratios = [
sum(normalized_ratios[0:i])
for i in range(n+1)
]
scaled_distances = [
int(round(r * length))
for r in cumulative_ratios
]
return scaled_distances
def split(list_, n, max_ratio):
"""Slice a list into n randomly-sized parts.
max_ratio is the largest allowable ratio between the largest and the
smallest part.
"""
points = splitting_points(len(list_), n, ratio)
return [
list_[ points[i] : points[i+1] ]
for i in range(n)
]
您可以这样尝试:
for _ in range(10):
parts = split('abcdefghijklmnopqrstuvwxyz', 4, 2)
print([(len(part), part) for part in parts])
不良结果示例:
parts = split('abcdefghijklmnopqrstuvwxyz', 10, 2)
# lengths range from 1 to 4, not 2 to 4
[(3, 'abc'), (3, 'def'), (1, 'g'),
(4, 'hijk'), (3, 'lmn'), (2, 'op'),
(2, 'qr'), (3, 'stu'), (2, 'vw'),
(3, 'xyz')]