Division d'une liste en N parties d'une longueur à peu près égale
Quelle est la meilleure façon de diviser une liste en à peu près parties égales? Par exemple, si la liste contient 7 éléments et est divisé en 2 parties, nous voulons obtenir 3 éléments dans une partie, et l'autre doit avoir 4 éléments.
je cherche quelque chose comme even_split(L, n)
qui casse L
en n
pièces.
def chunks(L, n):
""" Yield successive n-sized chunks from L.
"""
for i in xrange(0, len(L), n):
yield L[i:i+n]
Le code ci-dessus donne des morceaux de 3, plutôt que 3 morceaux. Je pourrais tout simplement transpose (itération en cours et prendre le premier élément de chaque colonne, appel que la première partie, puis prendre la deuxième et de la mettre dans la partie deux, etc), mais qui détruit l'ordre des éléments.
22 réponses
En voici un qui pourrait marcher:
def chunkIt(seq, num):
avg = len(seq) / float(num)
out = []
last = 0.0
while last < len(seq):
out.append(seq[int(last):int(last + avg)])
last += avg
return out
test:
>>> chunkIt(range(10), 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]]
>>> chunkIt(range(11), 3)
[[0, 1, 2], [3, 4, 5, 6], [7, 8, 9, 10]]
>>> chunkIt(range(12), 3)
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
vous pouvez l'écrire assez simplement comme générateur de liste:
def split(a, n):
k, m = divmod(len(a), n)
return (a[i * k + min(i, m):(i + 1) * k + min(i + 1, m)] for i in xrange(n))
exemple:
>>> list(split(range(11), 3))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10]]
aussi longtemps que vous ne voulez rien de stupide comme des morceaux continus:
>>> def chunkify(lst,n):
... return [lst[i::n] for i in xrange(n)]
...
>>> chunkify(range(13), 3)
[[0, 3, 6, 9, 12], [1, 4, 7, 10], [2, 5, 8, 11]]
C'est la raison d'être pour numpy.array_split
*:
>>> L
[0, 1, 2, 3, 4, 5, 6, 7]
>>> print(*np.array_split(L, 3))
[0 1 2] [3 4 5] [6 7]
>>> print(*np.array_split(range(10), 4))
[0 1 2] [3 4 5] [6 7] [8 9]
*crédit à Zéro Pirée dans la salle 6
changer le code pour donner n
morceaux plutôt que des morceaux de n
:
def chunks(l, n):
""" Yield n successive chunks from l.
"""
newn = int(len(l) / n)
for i in xrange(0, n-1):
yield l[i*newn:i*newn+newn]
yield l[n*newn-newn:]
l = range(56)
three_chunks = chunks (l, 3)
print three_chunks.next()
print three_chunks.next()
print three_chunks.next()
qui donne:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
[18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]
[36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]
cela assignera les éléments supplémentaires au groupe final qui n'est pas parfait mais bien dans votre spécification de" à peu près n parties égales": -) par cela, je veux dire 56 éléments seraient mieux que (19,19,18) alors que cela donne (18,18,20).
vous pouvez obtenir la sortie plus équilibrée avec le code suivant:
#!/usr/bin/python
def chunks(l, n):
""" Yield n successive chunks from l.
"""
newn = int(1.0 * len(l) / n + 0.5)
for i in xrange(0, n-1):
yield l[i*newn:i*newn+newn]
yield l[n*newn-newn:]
l = range(56)
three_chunks = chunks (l, 3)
print three_chunks.next()
print three_chunks.next()
print three_chunks.next()
qui produit:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
[19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37]
[38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]
si vous divisez n
éléments en gros k
morceaux vous pouvez faire n % k
Morceaux 1 élément plus grand que les autres morceaux pour distribuer les éléments supplémentaires.
le code suivant vous donnera la longueur des morceaux:
[(n // k) + (1 if i < (n % k) else 0) for i in range(k)]
exemple: n=11, k=3
résultats dans [4, 4, 3]
vous pouvez alors calculer facilement les indicateurs de départ pour les morceaux:
[i * (n // k) + min(i, n % k) for i in range(k)]
exemple: n=11, k=3
résultats dans [0, 4, 8]
en utilisant le i+1
TH morceau comme limite, nous obtenons que le i
th morceau de la liste l
avec len n
est
l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)]
comme dernière étape créez une liste à partir de tous les morceaux en utilisant la compréhension de liste:
[l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)] for i in range(k)]
exemple: n=11, k=3, l=range(n)
résultats dans [range(0, 4), range(4, 8), range(8, 11)]
En voici un qui ajoute None
pour rendre les listes de longueur égale
>>> from itertools import izip_longest
>>> def chunks(l, n):
""" Yield n successive chunks from l. Pads extra spaces with None
"""
return list(zip(*izip_longest(*[iter(l)]*n)))
>>> l=range(54)
>>> chunks(l,3)
[(0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51), (1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52), (2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53)]
>>> chunks(l,4)
[(0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52), (1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53), (2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, None), (3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, None)]
>>> chunks(l,5)
[(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50), (1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51), (2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52), (3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53), (4, 9, 14, 19, 24, 29, 34, 39, 44, 49, None)]
regarder numpy.split :
>>> a = numpy.array([1,2,3,4])
>>> numpy.split(a, 2)
[array([1, 2]), array([3, 4])]
voici ma solution:
def chunks(l, amount):
if amount < 1:
raise ValueError('amount must be positive integer')
chunk_len = len(l) // amount
leap_parts = len(l) % amount
remainder = amount // 2 # make it symmetrical
i = 0
while i < len(l):
remainder += leap_parts
end_index = i + chunk_len
if remainder >= amount:
remainder -= amount
end_index += 1
yield l[i:end_index]
i = end_index
produit
>>> list(chunks([1, 2, 3, 4, 5, 6, 7], 3))
[[1, 2], [3, 4, 5], [6, 7]]
voici un générateur qui peut gérer n'importe quel nombre (entier) positif de morceaux. Si le nombre de morceaux est plus grand que la liste d'entrées longueur de certains morceaux seront vides. Cet algorithme alterne entre des morceaux courts et des morceaux longs plutôt que de les séparer.
j'ai aussi inclus du code pour tester la fonction ragged_chunks
.
''' Split a list into "ragged" chunks
The size of each chunk is either the floor or ceiling of len(seq) / chunks
chunks can be > len(seq), in which case there will be empty chunks
Written by PM 2Ring 2017.03.30
'''
def ragged_chunks(seq, chunks):
size = len(seq)
start = 0
for i in range(1, chunks + 1):
stop = i * size // chunks
yield seq[start:stop]
start = stop
# test
def test_ragged_chunks(maxsize):
for size in range(0, maxsize):
seq = list(range(size))
for chunks in range(1, size + 1):
minwidth = size // chunks
#ceiling division
maxwidth = -(-size // chunks)
a = list(ragged_chunks(seq, chunks))
sizes = [len(u) for u in a]
deltas = all(minwidth <= u <= maxwidth for u in sizes)
assert all((sum(a, []) == seq, sum(sizes) == size, deltas))
return True
if test_ragged_chunks(100):
print('ok')
nous pouvons rendre ce légèrement plus efficace en exportant la multiplication dans l'appel range
, mais je pense que la version précédente est plus lisible (et plus sèche).
def ragged_chunks(seq, chunks):
size = len(seq)
start = 0
for i in range(size, size * chunks + 1, size):
stop = i // chunks
yield seq[start:stop]
start = stop
voir more_itertools.divide
:
n = 2
[list(x) for x in mit.divide(n, range(5, 11))]
# [[5, 6, 7], [8, 9, 10]]
[list(x) for x in mit.divide(n, range(5, 12))]
# [[5, 6, 7, 8], [9, 10, 11]]
installer via > pip install more_itertools
.
la Mise en oeuvre utilisation de numpy.méthode linspace.
spécifiez juste le nombre de parties dans lesquelles vous voulez que le tableau soit divisé.Les divisions seront de taille équivalente.
exemple :
import numpy as np
a=np.arange(10)
print "Input array:",a
parts=3
i=np.linspace(np.min(a),np.max(a)+1,parts+1)
i=np.array(i,dtype='uint16') # Indices should be floats
split_arr=[]
for ind in range(i.size-1):
split_arr.append(a[i[ind]:i[ind+1]]
print "Array split in to %d parts : "%(parts),split_arr
donne:
Input array: [0 1 2 3 4 5 6 7 8 9]
Array split in to 3 parts : [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8, 9])]
à l'Aide de la liste de compréhension:
def divide_list_to_chunks(list_, n):
return [list_[start::n] for start in range(n)]
cela fera la division par une seule expression:
>>> myList = range(18)
>>> parts = 5
>>> [myList[(i*len(myList))//parts:((i+1)*len(myList))//parts] for i in range(parts)]
[[0, 1, 2], [3, 4, 5, 6], [7, 8, 9], [10, 11, 12, 13], [14, 15, 16, 17]]
la liste dans cet exemple a la taille 18 et est divisée en 5 parties. La taille des pièces diffère pas de plus d'un élément.
ma solution, facile à comprendre
def split_list(lst, n):
splitted = []
for i in reversed(range(1, n + 1)):
split_point = len(lst)//i
splitted.append(lst[:split_point])
lst = lst[split_point:]
return splitted
et la plus courte Doublure sur cette page (écrite par ma fille)
def split(l, n):
return [l[int(i*len(l)/n):int((i+1)*len(l)/n-1)] for i in range(n)]
une autre façon serait quelque chose comme cela, l'idée ici est d'utiliser grouper, mais se débarrasser de None
. Dans ce cas, nous aurons tous "small_parts" formé à partir d'éléments lors de la première partie de la liste, et "larger_parts' de la fin de la liste. Longueur de "grandes parties" est len(small_parts) + 1. Nous devons considérer x comme deux sous-parties différentes.
from itertools import izip_longest
import numpy as np
def grouper(n, iterable, fillvalue=None): # This is grouper from itertools
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
def another_chunk(x,num):
extra_ele = len(x)%num #gives number of parts that will have an extra element
small_part = int(np.floor(len(x)/num)) #gives number of elements in a small part
new_x = list(grouper(small_part,x[:small_part*(num-extra_ele)]))
new_x.extend(list(grouper(small_part+1,x[small_part*(num-extra_ele):])))
return new_x
La façon dont je l'ai mis en place renvoie une liste de tuples:
>>> x = range(14)
>>> another_chunk(x,3)
[(0, 1, 2, 3), (4, 5, 6, 7, 8), (9, 10, 11, 12, 13)]
>>> another_chunk(x,4)
[(0, 1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13)]
>>> another_chunk(x,5)
[(0, 1), (2, 3, 4), (5, 6, 7), (8, 9, 10), (11, 12, 13)]
>>>
voici une autre variante qui répand les éléments" restants " également parmi tous les morceaux, un à la fois jusqu'à ce qu'il n'y en ait plus aucun. Dans cette implémentation, les plus gros morceaux se produisent au début du processus.
def chunks(l, k):
""" Yield k successive chunks from l."""
if k < 1:
yield []
raise StopIteration
n = len(l)
avg = n/k
remainders = n % k
start, end = 0, avg
while start < n:
if remainders > 0:
end = end + 1
remainders = remainders - 1
yield l[start:end]
start, end = end, end+avg
par exemple, générer 4 morceaux à partir d'une liste de 14 éléments:
>>> list(chunks(range(14), 4))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10], [11, 12, 13]]
>>> map(len, list(chunks(range(14), 4)))
[4, 4, 3, 3]
la même chose que job réponse, mais prend en compte des listes de taille inférieure au nombre de tronçonneuses.
def chunkify(lst,n):
[ lst[i::n] for i in xrange(n if n < len(lst) else len(lst)) ]
si n (nombre de morceaux) est de 7, et lst (la liste de fracture) est [1, 2, 3] les morceaux sont [[0], [1], [2]] au lieu de [[0], [1], [2], [], [], [], []]
vous pouvez également utiliser:
split=lambda x,n: x if not x else [x[:n]]+[split([] if not -(len(x)-n) else x[-(len(x)-n):],n)][0]
split([1,2,3,4,5,6,7,8,9],2)
[[1, 2], [3, 4], [5, 6], [7, 8], [9]]
#!/usr/bin/python
first_names = ['Steve', 'Jane', 'Sara', 'Mary','Jack','Bob', 'Bily', 'Boni', 'Chris','Sori', 'Will', 'Won','Li']
def chunks(l, n):
for i in range(0, len(l), n):
# Create an index range for l of n items:
yield l[i:i+n]
result = list(chunks(first_names, 5))
print result
tiré de ce lien , et c'est ce qui m'a aidé. J'ai eu une liste pré-définie.
dis que tu veux te diviser en 5 parties:
p1, p2, p3, p4, p5 = np.split(df, 5)
arrondir l'espace lin et l'utiliser comme un index est une solution plus facile que ce que propose amit12690.
function chunks=chunkit(array,num)
index = round(linspace(0,size(array,2),num+1));
chunks = cell(1,num);
for x = 1:num
chunks{x} = array(:,index(x)+1:index(x+1));
end
end