Saya memiliki daftar panjang yang sewenang-wenang, dan saya perlu membaginya menjadi potongan-potongan ukuran yang sama dan beroperasi di atasnya. Ada beberapa cara yang jelas untuk melakukan ini, seperti menyimpan penghitung dan dua daftar, dan ketika daftar kedua terisi, tambahkan ke daftar pertama dan kosongkan daftar kedua untuk putaran data berikutnya, tetapi ini berpotensi sangat mahal.
Saya bertanya-tanya apakah ada yang punya solusi yang baik untuk ini untuk daftar berapa pun, misalnya menggunakan generator.
Saya mencari sesuatu yang bermanfaat itertools
tetapi saya tidak dapat menemukan sesuatu yang jelas berguna. Namun, mungkin saja Anda melewatkannya.
Pertanyaan terkait: Apa cara paling "pythonic" untuk beralih pada daftar dalam potongan?
Jawaban:
Inilah generator yang menghasilkan bongkahan yang Anda inginkan:
Jika Anda menggunakan Python 2, Anda harus menggunakan
xrange()
alih-alihrange()
:Anda juga dapat menggunakan pemahaman daftar alih-alih menulis fungsi, meskipun merupakan ide bagus untuk merangkum operasi seperti ini dalam fungsi yang dinamai sehingga kode Anda lebih mudah dipahami. Python 3:
Versi Python 2:
sumber
Jika Anda menginginkan sesuatu yang super sederhana:
Gunakan
xrange()
sebagai gantirange()
dalam kasus Python 2.xsumber
max()
.Langsung dari dokumentasi Python (lama) (resep untuk itertools):
Versi saat ini, seperti yang disarankan oleh JFSebastian:
Saya kira mesin waktu Guido bekerja — bekerja — akan bekerja — akan berhasil — bekerja lagi.
Solusi ini berfungsi karena
[iter(iterable)]*n
(atau yang setara di versi sebelumnya) membuat satu iterator, berulangn
kali dalam daftar.izip_longest
kemudian secara efektif melakukan round-robin dari iterator "masing-masing"; karena ini adalah iterator yang sama, ia dikuatkan oleh setiap panggilan tersebut, menghasilkan setiap zip-roundrobin menghasilkan satu tuplen
item.sumber
list(grouper(3, range(10)))
pengembalian[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]
, dan semua tuple memiliki panjang 3. Tolong jelaskan komentar Anda karena saya tidak bisa memahaminya; apa yang Anda sebut suatu hal dan bagaimana Anda mendefinisikannya sebagai kelipatan 3 dalam “mengharapkan hal Anda menjadi kelipatan 3”? Terima kasih sebelumnya.itertools
pendekatan fungsional mewah menghasilkan beberapa lumpur yang tidak dapat dibaca, bila dibandingkan dengan implementasi python murni yang sederhana dan naifl==[1, 2, 3]
ituf(*l)
setara denganf(1, 2, 3)
. Lihat pertanyaan itu dan dokumentasi resmi .Saya tahu ini agak tua tetapi belum ada yang menyebutkan
numpy.array_split
:sumber
Aku heran tidak ada yang berpikir untuk menggunakan
iter
's bentuk dua-argumen :Demo:
Ini bekerja dengan iterable dan menghasilkan output dengan malas. Ini mengembalikan tuple daripada iterator, tapi saya pikir itu memiliki keanggunan tertentu. Itu juga tidak pad; jika Anda ingin bantalan, variasi sederhana di atas sudah cukup:
Demo:
Seperti
izip_longest
solusi berbasis, yang di atas selalu bantalan. Sejauh yang saya tahu, tidak ada resep itertools satu atau dua baris untuk fungsi yang secara opsional membalut. Dengan menggabungkan dua pendekatan di atas, yang ini cukup dekat:Demo:
Saya percaya ini adalah chunker terpendek yang diusulkan yang menawarkan padding opsional.
Seperti yang diamati oleh Tomasz Gandor , kedua chunker padding akan berhenti secara tak terduga jika mereka menemukan urutan panjang nilai pad. Berikut variasi terakhir yang mengatasi masalah itu dengan cara yang masuk akal:
Demo:
sumber
islice(it, size)
ekspresi dasar dan menyematkannya (seperti yang telah saya lakukan) dalam konstruksi lingkaran. Hanya Anda yang memikirkan versi dua argumen dariiter()
(saya benar-benar tidak menyadari), yang membuatnya super elegan (dan mungkin paling efektif-kinerja). Saya tidak tahu bahwa argumen pertama untukiter
perubahan ke fungsi 0-argumen ketika diberi sentinel. Anda mengembalikan iterator (pot. Infinite) dari chunks, dapat menggunakan iterator (pot. Infinite) sebagai input, tidak memilikilen()
dan tidak ada irisan array. Luar biasa!it
iterator. Kedua, dan yang paling penting - Anda akan berakhir sebelum waktunya jika sepotongpadval
benar - benar ada di iterable Anda, dan harus diproses.izip_longest
pendekatan, misalnya - saya kira itu mungkin kompromi yang rumit. Tapi ... bukankahpadval
masalah dibagikan oleh setiap jawaban di sini yang menawarkanpadval
parameter?()
sebagai penjaga, tidak berfungsi dengan benar. Ini karenatuple(islice(it, size))
menghasilkan()
ketikait
kosong.)Berikut adalah generator yang bekerja pada iterables yang sewenang-wenang:
Contoh:
sumber
sumber
map(None, iter)
sama denganizip_longest(iter)
.*
di depan Anda iterator tuple? Mungkin dalam teks jawaban Anda, tetapi saya perhatikan bahwa*
menggunakan cara itu di Python sebelumnya. Terima kasih!Sederhana namun elegan
atau jika Anda lebih suka:
sumber
1
danl
tidak bisa dibedakan. Apa adanya0
danO
. Dan terkadang bahkanI
dan1
.print [l[x:x+10] for x in xrange(1, len(l), 10)]
range
.Kritik dari jawaban lain di sini:
Tidak satu pun dari jawaban ini yang berukuran rata, mereka semua meninggalkan potongan pada akhirnya, sehingga tidak sepenuhnya seimbang. Jika Anda menggunakan fungsi-fungsi ini untuk mendistribusikan pekerjaan, Anda sudah memiliki prospek yang mungkin diselesaikan jauh di depan yang lain, sehingga Anda tidak akan melakukan apa-apa sementara yang lain terus bekerja keras.
Misalnya, jawaban teratas saat ini berakhir dengan:
Aku hanya benci keruntuhan itu pada akhirnya!
Lainnya, seperti
list(grouper(3, xrange(7)))
, danchunk(xrange(7), 3)
keduanya kembali:[(0, 1, 2), (3, 4, 5), (6, None, None)]
. ItuNone
hanya padding, dan agak tidak menurut saya. Mereka TIDAK secara merata memotong iterables.Mengapa kita tidak bisa membagi ini lebih baik?
Solusi Saya
Berikut adalah solusi yang seimbang, diadaptasi dari fungsi yang saya gunakan dalam produksi (Catatan Python 3 untuk menggantikan
xrange
denganrange
):Dan saya membuat generator yang melakukan hal yang sama jika Anda memasukkannya ke dalam daftar:
Dan akhirnya, karena saya melihat bahwa semua fungsi di atas mengembalikan elemen dalam urutan yang berdekatan (seperti yang diberikan):
Keluaran
Untuk mengujinya:
Yang mencetak:
Perhatikan bahwa generator yang berdekatan memberikan potongan dalam pola panjang yang sama dengan dua lainnya, tetapi item semuanya dalam urutan, dan mereka dibagi secara merata karena orang dapat membagi daftar elemen diskrit.
sumber
list(grouper(3, xrange(7)))
dan yang kedua,chunk(xrange(7), 3)
keduanya kembali:[(0, 1, 2), (3, 4, 5), (6, None, None)]
. ItuNone
hanya padding, dan agak tidak menurut saya. Mereka TIDAK secara merata memotong iterables. Terima kasih atas penilaian Anda!import pandas as pd; [pd.DataFrame(np.arange(7))[i::3] for i in xrange(3)]
Saya melihat jawaban Python-ish yang paling mengagumkan dalam duplikat dari pertanyaan ini:
Anda dapat membuat n-tuple untuk n apa pun. Jika
a = range(1, 15)
, maka hasilnya adalah:Jika daftar ini dibagi secara merata, maka Anda dapat mengganti
zip_longest
denganzip
, jika tidak, triplet(13, 14, None)
akan hilang. Python 3 digunakan di atas. Untuk Python 2, gunakanizip_longest
.sumber
zip(i, i, i, ... i)
dengan argumen "chunk_size" ke zip () dapat ditulis sebagaizip(*[i]*chunk_size)
Apakah itu ide yang bagus atau tidak bisa diperdebatkan, tentu saja.zip_longest
harus digunakan, seperti yang dilakukan di: stackoverflow.com/a/434411/1959808range(1, 15)
elemen yang sudah hilang, karena ada 14 elemenrange(1, 15)
, bukan 15.Jika Anda tahu ukuran daftar:
Jika Anda tidak (iterator):
Dalam kasus yang terakhir, ini dapat diulang dengan cara yang lebih indah jika Anda bisa yakin bahwa urutannya selalu berisi sejumlah bongkahan dengan ukuran tertentu (yaitu tidak ada potongan terakhir yang tidak lengkap).
sumber
The Toolz perpustakaan memiliki
partition
fungsi untuk ini:sumber
Jika Anda memiliki ukuran chunk 3 misalnya, Anda bisa melakukannya:
sumber: http://code.activestate.com/recipes/303060-group-a-list-into- berikutnyaential-n-tuples/
Saya akan menggunakan ini ketika ukuran chunk saya adalah angka tetap yang dapat saya ketik, misalnya '3', dan tidak akan pernah berubah.
sumber
Saya suka versi dokumen Python yang diusulkan oleh tzot dan JFSebastian, tetapi memiliki dua kekurangan:
Saya banyak menggunakan ini dalam kode saya:
UPDATE: Versi potongan malas:
sumber
while True
loop?StopIteration
ketikatuple
kosong daniterable.next()
dieksekusi. Tidak bekerja dengan baik di Python modern, di mana keluar generator harus dilakukanreturn
, bukan menaikkanStopIteration
. A ditry/except StopIteration: return
sekitar seluruh loop (dan berubahiterable.next()
menjadinext(iterable)
untuk versi lintas versi) memperbaikinya dengan overhead minimal.Di mana AA adalah array, SS adalah ukuran chunk. Sebagai contoh:
sumber
Saya ingin tahu tentang kinerja berbagai pendekatan dan ini dia:
Diuji pada Python 3.5.1
Hasil:
sumber
time
perpustakaan bukanlah ide bagus ketika kita memilikitimeit
modulkode:
hasil:
sumber
Anda juga dapat menggunakan
get_chunks
fungsiutilspie
perpustakaan sebagai:Anda dapat menginstal
utilspie
melalui pip:Penafian: Saya adalah pencipta perpustakaan utilspie .
sumber
Pada titik ini, saya pikir kita perlu generator rekursif , untuk berjaga-jaga ...
Dengan python 2:
Dengan python 3:
Juga, dalam kasus invasi Alien besar-besaran, generator rekursif yang dihiasi mungkin menjadi berguna:
sumber
Dengan Ekspresi Penugasan dalam Python 3.8 menjadi cukup bagus:
Ini berfungsi pada iterable sewenang-wenang, bukan hanya daftar.
sumber
heh, satu versi baris
sumber
def chunk
alih-alihchunk=lambda
memiliki .__ name__ atribut 'chunk' alih-alih '<lambda>'. Nama spesifik lebih berguna di traceback.<lamba>
atau tidak, paling tidak, perbedaan penting.pemakaian:
sumber
Versi lain yang lebih eksplisit.
sumber
Tanpa memanggil len () yang bagus untuk daftar besar:
Dan ini untuk iterables:
Rasa fungsional di atas:
ATAU:
ATAU:
sumber
len()
daftar besar; ini adalah operasi waktu konstan.Berikut adalah daftar pendekatan tambahan:
Diberikan
Kode
Perpustakaan Standar
more_itertools
+Referensi
zip_longest
( pos terkait , pos terkait )setdefault
(hasil yang dipesan membutuhkan Python 3.6+)collections.defaultdict
(hasil yang dipesan membutuhkan Python 3.6+)more_itertools.chunked
( terkait diposting )more_itertools.sliced
more_itertools.grouper
( pos terkait )more_itertools.windowed
(lihat jugastagger
,zip_offset
)+ Perpustakaan pihak ketiga yang mengimplementasikan resep itertools dan banyak lagi.
> pip install more_itertools
sumber
Lihat referensi ini
Python3
sumber
zip(*[iter(range(7))]*3)
Hanya mengembalikan[(0, 1, 2), (3, 4, 5)]
dan melupakan6
dari input.Karena semua orang di sini berbicara tentang iterator.
boltons
memiliki metode sempurna untuk itu, disebutiterutils.chunked_iter
.Keluaran:
Tapi jika Anda tidak ingin menjadi rahmat pada memori, Anda dapat menggunakan tua-cara dan menyimpan penuh
list
di tempat pertama denganiterutils.chunked
.sumber
Satu lagi solusi
sumber
sumber
Pertimbangkan untuk menggunakan potongan matplotlib.cbook
sebagai contoh:
sumber