根据Python中的一组索引将列表拆分成不同的部分
根据任意数量的索引将列表分成多个部分,最好的办法是什么? 例如给出下面的代码
indexes = [5, 12, 17] list = range(20)
返回这样的东西
part1 = list[:5] part2 = list[5:12] part3 = list[12:17] part4 = list[17:]
如果没有索引,它应该返回整个列表。
这是我能想到的最简单,最pythonic的解决scheme:
def partition(alist, indices): return [alist[i:j] for i, j in zip([0]+indices, indices+[None])]
如果input非常大,那么迭代器解决scheme应该更方便:
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)
当然,非常非常懒惰的解决scheme(如果您不介意获取数组而不是列表,但无论如何,您总是可以将它们还原为列表):
import numpy partition = numpy.split
我会有兴趣看到更多的Pythonic这样做的方式也。 但这是一个糟糕的解决scheme。 您将需要添加检查empry索引列表。
有些东西是:
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]]
我的解决scheme与Il-Bhima相似。
>>> def parts(list_, indices): ... indices = [0]+indices+[len(list_)] ... return [list_[v:indices[k+1]] for k, v in enumerate(indices[:-1])]
替代方法
如果你愿意稍微改变你input指数的方式,从绝对指数到相对的(即从[5, 12, 17]
到[5, 7, 5]
,下面也会给你所需的输出,而不会创build中介列表。
>>> 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
语句,而不是像itertools,zip(),None作为一个标记,列表parsing,whizzbang的东西…
😉
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's使数组的三个副本:[0] +索引副本,([0] +索引)+ []再次复制,并且索引[: – 1]将第三次复制。 Il-Bhima制作五份。 (当然,我不计算回报价值。)
这些可以减less(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()