根据Python中的一组索引将列表拆分为多个部分

时间:2009-07-29 07:16:25

标签: python list

根据任意数量的索引将列表拆分为多个部分的最佳方法是什么?例如。给出以下代码

indexes = [5, 12, 17]
list = range(20)

返回类似这样的内容

part1 = list[:5]
part2 = list[5:12]
part3 = list[12:17]
part4 = list[17:]

如果没有索引,则应返回整个列表。

9 个答案:

答案 0 :(得分:48)

这是我能想到的最简单,最灵活的解决方案:

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

答案 1 :(得分:9)

我有兴趣看到更多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]]

答案 2 :(得分:7)

我的解决方案类似于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])]

答案 3 :(得分:4)

>>> 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(),无作为哨兵,列表推导等的whizzbang东西,......

- )

答案 4 :(得分:2)

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

答案 5 :(得分:0)

这就是我能想到的全部

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

答案 6 :(得分:0)

Cide's制作三个数组副本:[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()的需要。)< / p>

答案 7 :(得分:0)

这是另一个答案。

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

答案 8 :(得分:-1)

指数的复数是指数。追求简单/可读性。

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