Kā sadalīt sarakstu vienāda lieluma daļās?

Man ir patvaļīga garuma saraksts, un man tas jāsadala vienāda lieluma gabalos un ar to jādarbojas. Ir daži acīmredzami veidi, kā to izdarīt, piemēram, saglabāt skaitītāju un divus sarakstus, un, kad otrais saraksts piepildās, pievienot to pirmajam sarakstam un iztukšot otro sarakstu nākamajai datu kārtai, bet tas ir potenciāli ārkārtīgi dārgi.

Mani interesēja, vai kādam ir labs risinājums, kā to izdarīt jebkura garuma sarakstiem, piemēram, izmantojot ģeneratorus.

Es meklēju kaut ko noderīgu itertools, bet neko acīmredzami noderīgu nevarēju atrast. Iespējams, ka esmu kaut ko palaidis garām.

Saistīts jautājums: Kāds ir "pitoniskākais" veids, kā iterēt sarakstu pa daļām?.

Risinājums

Šeit ir ģenerators, kas ļauj iegūt vēlamos gabaliņus:

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]

import pprint
pprint.pprint(list(chunks(range(10, 75), 10)))
[[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]]

Ja izmantojat Python 2, jums vajadzētu izmantot xrange(), nevis range():

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in xrange(0, len(l), n):
        yield l[i:i + n]

Varat arī vienkārši izmantot saraksta izpratni, nevis rakstīt funkciju, lai gan šāda veida operācijas ir labi iekapsulēt nosauktās funkcijās, lai jūsu kods būtu vieglāk saprotams. Python 3:

[l[i:i + n] for i in range(0, len(l), n)]

Python 2 versija:

[l[i:i + n] for i in xrange(0, len(l), n)]
Komentāri (10)

Šeit ir ģenerators, kas darbojas ar patvaļīgām iterablēm:

def split_seq(iterable, size):
    it = iter(iterable)
    item = list(itertools.islice(it, size))
    while item:
        yield item
        item = list(itertools.islice(it, size))

Piemērs:

>>> import pprint
>>> pprint.pprint(list(split_seq(xrange(75), 10)))
[[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]]
Komentāri (0)

Ja jūs zināt saraksta lielumu:

def SplitList(mylist, chunk_size):
    return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]

Ja nezini (iterators):

def IterChunks(sequence, chunk_size):
    res = []
    for item in sequence:
        res.append(item)
        if len(res) >= chunk_size:
            yield res
            res = []
    if res:
        yield res  # yield the last, incomplete, portion

Pēdējā gadījumā to var pārfrāzēt skaistāk, ja var būt pārliecināts, ka secībā vienmēr ir vesels skaits dotā lieluma gabalu (t.i., nav nepilnīga pēdējā gabala).

Komentāri (1)