52 votes

Diviser une liste en parties en fonction d'un ensemble d'index en Python

Quelle est la meilleure façon de diviser une liste en parties basées sur un nombre arbitraire d'index ? Par exemple, étant donné le code ci-dessous

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

retourner quelque chose comme ceci

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

S'il n'y a pas d'index, il devrait retourner la liste entière.

49voto

fortran Points 26495

C'est la solution la plus simple et la plus pythique à laquelle je puisse penser :

def partition(alist, indices):
    return [alist[i:j] for i, j in zip([0]+indices, indices+[None])]

si les entrées sont très grandes, alors la solution des itérateurs devrait être plus pratique :

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)

et bien sûr, la solution du gars très, très paresseux (si cela ne vous dérange pas d'obtenir des tableaux au lieu de listes, mais de toute façon vous pouvez toujours les reconvertir en listes) :

import numpy
partition = numpy.split

9voto

kjfletch Points 2913

Je serais également intéressé de voir une façon plus pythique de faire cela. Mais c'est une solution médiocre. Il faudrait ajouter la vérification d'une liste d'indices d'empry.

Quelque chose du genre :

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

produit

[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16], [17, 18, 19]]

7voto

Cide Points 1901

Ma solution est similaire à celle d'Il-Bhima.

>>> def parts(list_, indices):
...     indices = [0]+indices+[len(list_)]
...     return [list_[v:indices[k+1]] for k, v in enumerate(indices[:-1])]

Approche alternative

Si vous êtes prêt à modifier légèrement la façon dont vous saisissez les indices, des indices absolus aux indices relatifs (c'est-à-dire de [5, 12, 17] à [5, 7, 5] la méthode ci-dessous vous donnera également le résultat souhaité, sans créer de listes intermédiaires.

>>> from itertools import islice
>>> def parts(list_, indices):
...     i = iter(list_)
...     return [list(islice(i, n)) for n in chain(indices, [None])]

5voto

John Machin Points 39706
>>> 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 : il utilise une for et il n'utilise pas de trucs géniaux comme itertools, zip(), None comme sentinelle, les compréhensions de listes, ...

;-)

2voto

anthony Points 15067
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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X