Bir listeyi eşit büyüklükte parçalara nasıl bölersiniz?

Elimde rastgele uzunlukta bir liste var ve onu eşit büyüklükte parçalara ayırıp üzerinde işlem yapmam gerekiyor. Bunu yapmanın, bir sayaç ve iki liste tutmak ve ikinci liste dolduğunda, ilk listeye eklemek ve bir sonraki veri turu için ikinci listeyi boşaltmak gibi bazı bariz yolları vardır, ancak bu potansiyel olarak son derece pahalıdır.

Herhangi bir uzunluktaki listeler için iyi bir çözümü olan var mı diye merak ediyordum, örneğin jeneratörler kullanarak.

itertools' içinde yararlı bir şeyler arıyordum ama açıkça yararlı bir şey bulamadım. Yine de kaçırmış olabilirim.

İlgili soru: Bir liste üzerinde yığınlar halinde yinelemenin en "pythonic" yolu nedir?

Çözüm

İşte size istediğiniz parçaları üreten bir jeneratör:

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

Eğer Python 2 kullanıyorsanız, range() yerine xrange() kullanmalısınız:

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

Ayrıca, bir fonksiyon yazmak yerine liste kavramayı da kullanabilirsiniz, ancak kodunuzun daha kolay anlaşılması için bu gibi işlemleri adlandırılmış fonksiyonlarda kapsüllemek iyi bir fikirdir. Python 3:

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

Python 2 sürümü:

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

İşte rastgele yinelenebilir dosyalar üzerinde çalışan bir üreteç:

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

Örnek:

>>> 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]]
Yorumlar (0)

Liste boyutunu biliyorsanız:

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

Eğer yapmazsanız (bir yineleyici):

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

İkinci durumda, dizinin her zaman belirli boyutta tam sayıda parça içerdiğinden emin olabilirseniz (yani tamamlanmamış bir son parça yoksa) daha güzel bir şekilde yeniden ifade edilebilir.

Yorumlar (1)