Die Aufteilung einer Liste in N Teile von etwa gleicher Länge
Frage
Was ist der beste Weg zum aufteilen einer Liste in rund zu gleichen teilen?Für Beispiel, wenn die Liste hat 7 Elemente, aufgeteilt in 2 Teile, wir möchten zu Holen Sie 3 Elemente in einem Teil, und die andere sollte die 4 Elemente.
Ich bin auf der Suche nach etwas wie even_split(L, n)
bricht L
in n
Teile.
def chunks(L, n):
""" Yield successive n-sized chunks from L.
"""
for i in xrange(0, len(L), n):
yield L[i:i+n]
Der obige code gibt Blöcken von 3, statt 3 Stücke.Ich konnte einfach transponieren (Iteration über dies und nehmen Sie das erste element jeder Spalte, nennen das Teil eine, dann die zweite und legen Sie es in Teil zwei, usw), aber das zerstört die Reihenfolge der Elemente.
Lösung
Hier ist eine, die funktionieren könnte:
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]]
Andere Tipps
Sie können es schreiben ziemlich einfach als Listen-Generator:
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))
Beispiel:
>>> list(split(range(11), 3))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10]]
Solange Sie nicht wollen, etwas albern wie kontinuierliche Brocken:
>>> 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]]
Dies ist die Daseinsberechtigung 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]
* Kredit Null Piraeus in Zimmer 6
Ändern Sie den Code, um die Ausbeute n
Chunks anstatt Brocken 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()
das gibt:
[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]
Damit werden die zusätzlichen Elemente der letzten Gruppe zuordnen, die nicht perfekt ist, aber auch in Ihrer Spezifikation von „grob N gleiche Teile“ :-) Damit meine ich 56 Elemente als besser wäre (19,19,18) während dies gibt (18,18,20).
Sie können den ausgeglichenere Ausgang mit dem folgenden Code erhalten:
#!/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()
die Ausgänge:
[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]
Wenn Sie teilen n
Elemente, die in etwa k
Stücke, die Sie machen können n % k
Stücke 1-element, größer als die anderen chunks zu verteilen, die zusätzlichen Elemente.
Der folgende code wird Ihnen die Länge der Stücke:
[(n // k) + (1 if i < (n % k) else 0) for i in range(k)]
Beispiel: n=11, k=3
Ergebnisse in [4, 4, 3]
Sie können leicht berechnen der start-indizes für die Stücke:
[i * (n // k) + min(i, n % k) for i in range(k)]
Beispiel: n=11, k=3
Ergebnisse in [0, 4, 8]
Mit der i+1
th chunk als die Grenze, die wir bekommen, dass die i
th chunk der Liste l
mit len n
ist
l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)]
Als letzten Schritt erstellen Sie eine Liste aller chunks mit list comprehension:
[l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)] for i in range(k)]
Beispiel: n=11, k=3, l=range(n)
Ergebnisse in [range(0, 4), range(4, 8), range(8, 11)]
Hier ist eine, die None
fügt die Listen gleich lang machen
>>> 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)]
Dies wird die Spaltung durch einen einzigen Ausdruck tun:
>>> 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]]
Die Liste in diesem Beispiel hat die Größe 18 und ist in 5 Teile geteilt. Die Größe der Teile unterscheidet sich in nicht mehr als einem Element.
Siehe 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]]
Installieren über > pip install more_itertools
.
Hier finden Sie aktuelle numpy.split :
>>> a = numpy.array([1,2,3,4])
>>> numpy.split(a, 2)
[array([1, 2]), array([3, 4])]
Implementierung numpy.linspace Methode.
Geben Sie einfach die Anzahl der Teile wollen Sie das Array in to.The Divisionen aufgeteilt wird von nahezu gleicher Größe sein.
Beispiel:
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
Gibt:
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])]
Hier ist meine Lösung:
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
Erzeugt
>>> list(chunks([1, 2, 3, 4, 5, 6, 7], 3))
[[1, 2], [3, 4, 5], [6, 7]]
Hier ist ein Generator, der eine positive (integer) Anzahl der Stücke verarbeiten kann. Wenn die Anzahl der Stücke größer als die Eingangslistenlänge ist, werden einige Stücke leer sein. Dieser Algorithmus wechselt zwischen kurzen und langen Stücken, anstatt sie Absonderungs.
Ich habe auch einige Codes zum Testen der ragged_chunks
Funktion enthalten.
''' 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')
Wir können das machen leicht effizienter durch die Multiplikation in den range
Aufruf exportieren, aber ich denke, die vorherige Version besser lesbar ist (und Trockner).
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
Mit Liste Verständnis:
def divide_list_to_chunks(list_, n):
return [list_[start::n] for start in range(n)]
Meine Lösung, leicht zu verstehen
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
Und kürzester Einzeiler auf dieser Seite (geschrieben von meinem Mädchen)
def split(l, n):
return [l[int(i*len(l)/n):int((i+1)*len(l)/n-1)] for i in range(n)]
sagen Sie in 5 Teile geteilt werden soll:
p1, p2, p3, p4, p5 = np.split(df, 5)
Ein anderer Weg wäre so etwas wie diese, die Idee hier ist, zu verwenden, grouper, aber loswerden None
.In diesem Fall haben wir Sie alle 'small_parts', gebildet aus Elementen an den ersten Teil der Liste, und 'larger_parts' aus dem später ein Teil der Liste.Länge von "größere Teile" ist len(small_parts) + 1.Müssen wir betrachten x als zwei verschiedenen sub-parts.
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
Die Art, wie ich es eingerichtet haben gibt eine Liste von Tupeln:
>>> 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)]
>>>
Hier ist eine andere Variante, dass die Spreads die „restlichen“ Elemente gleichmäßig unter allen Stücken, einer nach dem anderen, bis es keine mehr. Bei dieser Implementierung treten die größeren Brocken am Anfang des Prozesses.
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
Beispiel 4 erzeugt Chunks aus einer Liste mit 14 Elementen:
>>> 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]
def chunkify(lst,n):
[ lst[i::n] for i in xrange(n if n < len(lst) else len(lst)) ]
, wenn n (Anzahl von Chunks) ist 7 und lst (die Liste zu teilen) ist [1, 2, 3] Die Brocken sind [[0], [1], [2]] anstelle von [[0] [1], [2], [], [], [], []]
Sie können auch verwendet werden:
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
Picked von diesem Link , und das war, was mir geholfen hat. Ich hatte eine vordefinierte Liste.
Ich habe in diesem Fall geschriebenen Code selbst:
def chunk_ports(port_start, port_end, portions):
if port_end < port_start:
return None
total = port_end - port_start + 1
fractions = int(math.floor(float(total) / portions))
results = []
# No enough to chuck.
if fractions < 1:
return None
# Reverse, so any additional items would be in the first range.
_e = port_end
for i in range(portions, 0, -1):
print "i", i
if i == 1:
_s = port_start
else:
_s = _e - fractions + 1
results.append((_s, _e))
_e = _s - 1
results.reverse()
return results
divide_ports (1, 10, 9) zurückkehren würde
[(1, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9), (10, 10)]
Dieser Code funktioniert für mich (Python3-kompatibel):
def chunkify(tab, num):
return [tab[i*num: i*num+num] for i in range(len(tab)//num+(1 if len(tab)%num else 0))]
Beispiel (für bytearray Typ, aber es funktioniert für Liste s auch):
b = bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08')
>>> chunkify(b,3)
[bytearray(b'\x01\x02\x03'), bytearray(b'\x04\x05\x06'), bytearray(b'\x07\x08')]
>>> chunkify(b,4)
[bytearray(b'\x01\x02\x03\x04'), bytearray(b'\x05\x06\x07\x08')]
Dies bietet Stücke von einer Länge von <= n> = 0
def
chunkify(lst, n):
num_chunks = int(math.ceil(len(lst) / float(n))) if n < len(lst) else 1
return [lst[n*i:n*(i+1)] for i in range(num_chunks)]
zum Beispiel
>>> chunkify(range(11), 3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
>>> chunkify(range(11), 8)
[[0, 1, 2, 3, 4, 5, 6, 7], [8, 9, 10]]
habe ich versucht, die meist Teil der Lösungen, aber sie taten es für meinen Fall nicht arbeiten, so dass ich eine neue Funktion zu machen, dass die Arbeit für die meisten Fälle und für jede Art von Array:
import math
def chunkIt(seq, num):
seqLen = len(seq)
total_chunks = math.ceil(seqLen / num)
items_per_chunk = num
out = []
last = 0
while last < seqLen:
out.append(seq[last:(last + items_per_chunk)])
last += items_per_chunk
return out
def evenly(l, n):
len_ = len(l)
split_size = len_ // n
split_size = n if not split_size else split_size
offsets = [i for i in range(0, len_, split_size)]
return [l[offset:offset + split_size] for offset in offsets]
Beispiel:
l = [a for a in range(97)]
sollte aus 10 Teilen bestehen werden, haben jeweils 9 Elemente mit Ausnahme des letzten.
Ausgang:
[[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, 56, 57, 58, 59, 60, 61, 62],
[63, 64, 65, 66, 67, 68, 69, 70, 71],
[72, 73, 74, 75, 76, 77, 78, 79, 80],
[81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96]]
Abgerundet wird das linspace und deren Verwendung als Index ist eine einfachere Lösung als das, was amit12690 schlägt.
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