[英]Split a list into parts based on a set of indexes in Python
基于任意数量的索引将列表拆分为多个部分的最佳方法是什么? 例如,给出下面的代码
indexes = [5, 12, 17]
list = range(20)
返回这样的东西
part1 = list[:5]
part2 = list[5:12]
part3 = list[12:17]
part4 = list[17:]
如果没有索引,则应返回整个列表。
这是我能想到的最简单,最pythonic的解决方案:
def partition(alist, indices):
return [alist[i:j] for i, j in zip([0]+indices, indices+[None])]
如果输入非常大,那么迭代器解决方案应该更方便:
from itertools import izip, chain
def partition(alist, indices):
pairs = izip(chain([0], indices), chain(indices, [None]))
return (alist[i:j] for i, j in pairs)
当然,非常非常懒惰的解决方案(如果你不介意获取数组而不是列表,但无论如何你总是可以将它们恢复为列表):
import numpy
partition = numpy.split
我也有兴趣看到更多的Pythonic方式。 但这是一个糟糕的解决方案。 您需要添加对空索引列表的检查。
有点像:
indexes = [5, 12, 17]
list = range(20)
output = []
prev = 0
for index in indexes:
output.append(list[prev:index])
prev = index
output.append(list[indexes[-1]:])
print output
产生
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16], [17, 18, 19]]
我的解决方案与Il-Bhima相似。
>>> def parts(list_, indices):
... indices = [0]+indices+[len(list_)]
... return [list_[v:indices[k+1]] for k, v in enumerate(indices[:-1])]
如果您愿意稍微改变输入索引的方式,从绝对索引到相对(即从[5, 12, 17]
到[5, 7, 5]
,下面也会给出所需的输出,而它不会创建中间列表。
>>> from itertools import islice
>>> def parts(list_, indices):
... i = iter(list_)
... return [list(islice(i, n)) for n in chain(indices, [None])]
>>> def burst_seq(seq, indices):
... startpos = 0
... for index in indices:
... yield seq[startpos:index]
... startpos = index
... yield seq[startpos:]
...
>>> list(burst_seq(range(20), [5, 12, 17]))
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16], [17, 18, 19]]
>>> list(burst_seq(range(20), []))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]]
>>> list(burst_seq(range(0), [5, 12, 17]))
[[], [], [], []]
>>>
Maxima mea culpa:它使用for
语句,它不使用whizzbang的东西,如itertools,zip(),None作为哨兵,列表推导,......
;-)
indices = [5, 12, 17]
input = range(20)
output = []
reduce(lambda x, y: output.append(input[x:y]) or y, indices + [len(input)], 0)
print output
这就是我能想到的一切
def partition(list_, indexes):
if indexes[0] != 0:
indexes = [0] + indexes
if indexes[-1] != len(list_):
indexes = indexes + [len(list_)]
return [ list_[a:b] for (a,b) in zip(indexes[:-1], indexes[1:])]
Cide的三个副本数组:[0] +索引副本,([0] +索引)+ []再次复制,索引[: - 1]将复制第三次。 Il-Bhima制作了五份。 (当然,我不计算返回值。)
那些可以减少(izip,islice),但这里是零拷贝版本:
def iterate_pairs(lst, indexes):
prev = 0
for i in indexes:
yield prev, i
prev = i
yield prev, len(lst)
def partition(lst, indexes):
for first, last in iterate_pairs(lst, indexes):
yield lst[first:last]
indexes = [5, 12, 17]
lst = range(20)
print [l for l in partition(lst, indexes)]
当然,与解释Python相比,数组副本相当便宜(本机代码),但这还有另一个优点:它易于重用,可以直接改变数据:
for first, last in iterate_pairs(lst, indexes):
for i in range(first, last):
lst[i] = first
print lst
# [0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 12, 12, 12, 12, 12, 17, 17, 17]
(这就是我将索引传递给iterate_pairs的原因。如果你不关心这个,你可以删除那个参数,最后一行是“yield prev,None”,这是所有partition()的需要。)
这是另一个答案。
def partition(l, indexes):
result, indexes = [], indexes+[len(l)]
reduce(lambda x, y: result.append(l[x:y]) or y, indexes, 0)
return result
它支持负面索引等。
>>> partition([1,2,3,4,5], [1, -1])
[[1], [2, 3, 4], [5]]
>>>
索引的复数是指数。 追求简单/可读性。
indices = [5, 12, 17]
input = range(20)
output = []
for i in reversed(indices):
output.append(input[i:])
input[i:] = []
output.append(input)
while len(output):
print output.pop()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.