Cukup sering, saya merasa perlu memproses daftar secara berpasangan. Saya bertanya-tanya mana yang akan menjadi cara pythonic dan efisien untuk melakukannya, dan menemukan ini di Google:
pairs = zip(t[::2], t[1::2])
Saya pikir itu cukup pythonic, tetapi setelah diskusi baru-baru ini yang melibatkan idiom versus efisiensi , saya memutuskan untuk melakukan beberapa tes:
import time
from itertools import islice, izip
def pairs_1(t):
return zip(t[::2], t[1::2])
def pairs_2(t):
return izip(t[::2], t[1::2])
def pairs_3(t):
return izip(islice(t,None,None,2), islice(t,1,None,2))
A = range(10000)
B = xrange(len(A))
def pairs_4(t):
# ignore value of t!
t = B
return izip(islice(t,None,None,2), islice(t,1,None,2))
for f in pairs_1, pairs_2, pairs_3, pairs_4:
# time the pairing
s = time.time()
for i in range(1000):
p = f(A)
t1 = time.time() - s
# time using the pairs
s = time.time()
for i in range(1000):
p = f(A)
for a, b in p:
pass
t2 = time.time() - s
print t1, t2, t2-t1
Ini adalah hasil di komputer saya:
1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578
Jika saya menafsirkannya dengan benar, itu berarti penerapan daftar, pengindeksan daftar, dan pemotongan daftar dengan Python sangat efisien. Hasilnya menghibur dan tidak terduga.
Apakah ada cara lain yang "lebih baik" untuk melintasi daftar secara berpasangan?
Perhatikan bahwa jika daftar memiliki jumlah elemen ganjil maka yang terakhir tidak akan ada di pasangan mana pun.
Cara manakah yang benar untuk memastikan bahwa semua elemen disertakan?
Saya menambahkan dua saran ini dari jawaban tes:
def pairwise(t):
it = iter(t)
return izip(it, it)
def chunkwise(t, size=2):
it = iter(t)
return izip(*[it]*size)
Inilah hasilnya:
0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176
Hasil sejauh ini
Paling pythonic dan sangat efisien:
pairs = izip(t[::2], t[1::2])
Paling efisien dan sangat pythonic:
pairs = izip(*[iter(t)]*2)
Butuh beberapa saat bagi saya untuk menjelaskan bahwa jawaban pertama menggunakan dua iterator sedangkan yang kedua menggunakan satu satu.
Untuk menangani urutan dengan jumlah elemen ganjil, sarannya adalah menambah urutan asli dengan menambahkan satu elemen ( None
) yang dipasangkan dengan elemen terakhir sebelumnya, sesuatu yang dapat dicapai dengan itertools.izip_longest()
.
Akhirnya
Perhatikan bahwa, dalam Python 3.x, zip()
berperilaku sebagai itertools.izip()
, dan itertools.izip()
hilang.
timeit
modul.Jawaban:
Cara favorit saya untuk melakukannya:
Saat Anda ingin memasangkan semua elemen, Anda jelas membutuhkan fillvalue:
sumber
itertools
resep.izip(*[iter(t)]*size)
Saya akan mengatakan bahwa solusi awal Anda
pairs = zip(t[::2], t[1::2])
adalah yang terbaik karena paling mudah dibaca (dan di Python 3,zip
secara otomatis mengembalikan iterator daripada daftar).Untuk memastikan bahwa semua elemen disertakan, Anda cukup memperpanjang daftar dengan
None
.Kemudian, jika daftarnya memiliki jumlah elemen ganjil, pasangan terakhirnya adalah
(item, None)
.sumber
Saya mulai dengan penafian kecil - jangan gunakan kode di bawah ini. Itu sama sekali bukan Pythonic, saya menulis hanya untuk bersenang-senang. Ini mirip dengan
pairwise
fungsi @ THC4k tetapi menggunakaniter
dan menutuplambda
. Itu tidak menggunakanitertools
modul dan tidak mendukungfillvalue
. Saya taruh di sini karena seseorang mungkin menganggapnya menarik:sumber
Sejauh kebanyakan pythonic pergi, saya akan mengatakan resep yang disediakan dalam dokumen sumber python (beberapa di antaranya terlihat sangat mirip dengan jawaban yang disediakan @JochenRitzel) mungkin adalah pilihan terbaik Anda;)
Pada python modern Anda hanya perlu menggunakan
zip_longest(*args, fillvalue=fillvalue)
sesuai dengan halaman dokumen yang sesuai .sumber
Saya tidak dapat mengatakan dengan pasti tetapi saya meragukannya: Setiap traversal lain akan menyertakan lebih banyak kode Python yang harus ditafsirkan. Fungsi bawaan seperti zip () ditulis dalam C yang jauh lebih cepat.
Periksa panjang daftar dan jika ganjil (
len(list) & 1 == 1
), salin daftar dan tambahkan item.sumber
sumber
Lakukan saja:
sumber
list(zip(l, l[1:]))
, dan tidak membagi daftar menjadi pasangan.Berikut contoh pembuatan pasangan / kaki dengan menggunakan generator. Generator bebas dari batas tumpukan
Contoh:
Keluaran:
sumber
[(0, 1), (2, 3), (4, 5)....
zip()
sudah mengembalikan generator dengan Python 3.x, @VladBezdenUntuk berjaga-jaga jika seseorang membutuhkan jawaban dari segi algoritme, ini dia:
Tetapi perhatikan bahwa daftar asli Anda juga akan dikurangi menjadi elemen terakhirnya, karena Anda menggunakannya
pop
.sumber