Anda memerlukan pairwise()(atau grouped()) implementasi.
Untuk Python 2:
from itertools import izip
def pairwise(iterable):"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)return izip(a, a)for x, y in pairwise(l):print"%d + %d = %d"%(x, y, x + y)
Atau, lebih umum:
from itertools import izip
def grouped(iterable, n):"s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."return izip(*[iter(iterable)]*n)for x, y in grouped(l,2):print"%d + %d = %d"%(x, y, x + y)
Di Python 3, Anda bisa mengganti izipdengan zip()fungsi bawaan, dan lepaskanimport .
Semua kredit untuk martineau untuk jawaban atas pertanyaan saya , saya telah menemukan ini sangat efisien karena hanya mengulangi sekali dalam daftar dan tidak membuat daftar yang tidak perlu dalam proses.
NB : Ini tidak harus bingung dengan pairwiseresep dalam itertoolsdokumentasi Python sendiri , yang menghasilkan s -> (s0, s1), (s1, s2), (s2, s3), ..., seperti yang ditunjukkan oleh @ lazyr dalam komentar.
Tambahan kecil untuk mereka yang ingin melakukan pengecekan ketik dengan mypy pada Python 3:
from typing importIterable,Tuple,TypeVar
T =TypeVar("T")def grouped(iterable:Iterable[T], n=2)->Iterable[Tuple[T,...]]:"""s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..."""return zip(*[iter(iterable)]* n)
Jangan bingung dengan fungsi berpasangan yang disarankan di bagian resep itertools , yang menghasilkans -> (s0,s1), (s1,s2), (s2, s3), ...
Lauritz V. Thaulow
1
Itu melakukan hal yang berbeda. Versi Anda hanya menghasilkan setengah jumlah pasangan dibandingkan dengan itertoolsfungsi resep dengan nama yang sama. Tentu saja milikmu lebih cepat ...
Sven Marnach
Hah? Fungsi Anda dan fungsi yang saya maksudkan untuk melakukan hal-hal yang berbeda, dan itulah inti dari komentar saya.
Lauritz V. Thaulow
5
HATI-HATI! Menggunakan fungsi-fungsi ini menempatkan Anda pada risiko tidak mengulangi elemen-elemen terakhir dari iterable. Contoh: daftar (dikelompokkan ([1,2,3], 2)) >>> [(1, 2)] .. saat Anda mengharapkan [(1,2), (3,)]
egafni
4
@ Erik49: Dalam kasus yang ditentukan dalam pertanyaan, tidak masuk akal untuk memiliki tuple 'tidak lengkap'. Jika Anda ingin menyertakan tupel tidak lengkap, Anda bisa menggunakan izip_longest()bukan izip(). Misalnya: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))-> [(1, 2), (3, 0)]. Semoga ini membantu.
Johnsyweb
191
Anda perlu dua elemen, jadi
data =[1,2,3,4,5,6]for i,k in zip(data[0::2], data[1::2]):print str(i),'+', str(k),'=', str(i+k)
Dimana:
data[0::2] artinya membuat subset kumpulan elemen itu (index % 2 == 0)
zip(x,y) membuat koleksi tuple dari koleksi x dan y elemen indeks yang sama.
Ini juga dapat diperpanjang jika diperlukan lebih dari dua elemen. Misalnyafor i, j, k in zip(data[0::3], data[1::3], data[2::3]):
lifebalance
19
Jauh lebih bersih daripada menarik impor dan mendefinisikan fungsi!
kmarsh
7
@kmarsh: Tapi ini hanya bekerja pada urutan, fungsinya bekerja pada semua iterable; dan ini menggunakan ruang ekstra O (N), fungsinya tidak; di sisi lain, ini biasanya lebih cepat. Ada alasan bagus untuk memilih satu atau yang lain; takut importbukan salah satu dari mereka.
abarnert
77
>>> l =[1,2,3,4,5,6]>>> zip(l,l[1:])[(1,2),(2,3),(3,4),(4,5),(5,6)]>>> zip(l,l[1:])[::2][(1,2),(3,4),(5,6)]>>>[a+b for a,b in zip(l,l[1:])[::2]][3,7,11]>>>["%d + %d = %d"%(a,b,a+b)for a,b in zip(l,l[1:])[::2]]['1 + 2 = 3','3 + 4 = 7','5 + 6 = 11']
Ini tidak bekerja pada Python-3.6.0 tetapi masih bekerja pada Python-2.7.10
Hamid Rohani
6
@HamidRohani zipmengembalikan zipobjek dengan Python 3, yang tidak dapat disubkripsikan . Itu perlu dikonversi ke urutan ( list,, tupledll) terlebih dahulu, tetapi "tidak bekerja" adalah sedikit peregangan.
vaultah
58
Solusi sederhana.
l = [1, 2, 3, 4, 5, 6]
untuk saya dalam kisaran (0, len (l), 2):
mencetak str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
bagaimana jika daftar Anda tidak genap, dan Anda ingin menunjukkan nomor terakhir seperti apa adanya?
Hans de Jong
@HansdeJong tidak mengerti Anda. Tolong jelaskan sedikit lebih banyak.
taskinoor
2
Terima kasih. Saya sudah tahu bagaimana melakukannya. Masalahnya adalah jika Anda memiliki daftar yang bahkan tidak memiliki jumlah angka di dalamnya, itu akan mendapatkan kesalahan indeks. Mengatasinya dengan mencoba: kecuali:
Hans de Jong
Atau ((l[i], l[i+1])for i in range(0, len(l), 2))untuk generator, dapat dengan mudah dimodifikasi untuk tupel yang lebih panjang.
Basel Shishani
44
Sementara semua jawaban yang digunakan zipsudah benar, saya menemukan bahwa mengimplementasikan sendiri fungsionalitas itu mengarah ke kode yang lebih mudah dibaca:
def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:# no more elements in the iteratorreturn
Bagian ini it = iter(it)memastikan bahwa itsebenarnya merupakan iterator, bukan hanya iterable. Jika itsudah merupakan iterator, baris ini adalah no-op.
Solusi ini memungkinkan generalisasi untuk ukuran tupel> 2
guilloptero
1
Solusi ini juga berfungsi jika ithanya merupakan iterator dan bukan iterable. Solusi lain tampaknya bergantung pada kemungkinan untuk membuat dua iterator independen untuk urutan.
meroket
Saya menemukan pendekatan ini di stackoverflow.com/a/16815056/2480481 sebelum melihat jawaban ini. Lebih bersih, lebih mudah daripada berurusan dengan zip ().
m3nda
2
Saya suka itu memungkinkan untuk menghindari penggunaan memori tiga kali lipat sebagai jawaban yang diterima.
Kentzo
Ini tidak berfungsi dengan baik dengan forloop di Python 3.5+ karena PEP 479 , yang menggantikan setiap StopIterationpeningkatan dalam generator dengan a RuntimeError.
sidney
28
Saya harap ini akan menjadi cara yang lebih elegan untuk melakukannya.
a =[1,2,3,4,5,6]
zip(a[::2], a[1::2])[(1,2),(3,4),(5,6)]
Jika Anda tertarik dengan kinerja, saya melakukan tolok ukur kecil (menggunakan perpustakaan saya simple_benchmark) untuk membandingkan kinerja solusi dan saya menyertakan fungsi dari salah satu paket saya:iteration_utilities.grouper
from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark importBenchmarkBuilder
bench =BenchmarkBuilder()@bench.add_function()defJohnsyweb(l):def pairwise(iterable):"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)return zip(a, a)for x, y in pairwise(l):pass@bench.add_function()defMargus(data):for i, k in zip(data[0::2], data[1::2]):pass@bench.add_function()def pyanon(l):
list(zip(l,l[1:]))[::2]@bench.add_function()def taskinoor(l):for i in range(0, len(l),2):
l[i], l[i+1]@bench.add_function()def mic_e(it):def pairwise(it):
it = iter(it)whileTrue:try:yield next(it), next(it)exceptStopIteration:returnfor a, b in pairwise(it):pass@bench.add_function()defMSeifert(it):for item1, item2 in grouper(it,2):pass
bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1,20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize']=(8,10)
benchmark_result.plot_both(relative_to=MSeifert)
Jadi, jika Anda menginginkan solusi tercepat tanpa dependensi eksternal, Anda mungkin harus menggunakan pendekatan yang diberikan oleh Johnysweb (pada saat penulisan ini adalah jawaban yang paling banyak dipilih dan diterima).
Jika Anda tidak keberatan dengan ketergantungan tambahan maka grouperdari iteration_utilitiesmungkin akan sedikit lebih cepat.
Pikiran tambahan
Beberapa pendekatan memiliki beberapa batasan, yang belum dibahas di sini.
Misalnya beberapa solusi hanya bekerja untuk urutan (yaitu daftar, string, dll.), Misalnya solusi Margus / pyanon / taskinoor yang menggunakan pengindeksan sementara solusi lain bekerja pada setiap iterable (yaitu urutan dan generator, iterator) seperti Johnysweb / mic_e / solusi saya.
Kemudian Johnysweb juga memberikan solusi yang berfungsi untuk ukuran selain 2 sedangkan jawaban lainnya tidak (oke, the iteration_utilities.grouper juga memungkinkan pengaturan jumlah elemen ke "grup").
Lalu ada juga pertanyaan tentang apa yang harus terjadi jika ada jumlah elemen ganjil dalam daftar. Haruskah barang yang tersisa dibubarkan? Haruskah daftar itu diisi dengan empuk agar ukurannya rata? Haruskah barang yang tersisa dikembalikan sebagai tunggal? Jawaban lainnya tidak membahas hal ini secara langsung, namun jika saya tidak mengabaikan apa pun mereka semua mengikuti pendekatan bahwa item yang tersisa harus diberhentikan (kecuali untuk jawaban taskinoors - yang benar-benar akan meningkatkan Pengecualian).
Dengan grouperAnda dapat memutuskan apa yang ingin Anda lakukan:
zip(*iterable) mengembalikan tuple dengan elemen berikutnya dari setiap iterable.
l[::2] mengembalikan elemen ke-1, ke-3, ke-5, dll. dari daftar: tanda titik dua menunjukkan bahwa irisan dimulai di awal karena tidak ada angka di belakangnya, tanda titik dua hanya diperlukan jika Anda menginginkan langkah 'pada irisan '(dalam hal ini 2).
l[1::2]melakukan hal yang sama tetapi dimulai pada elemen kedua daftar sehingga mengembalikan elemen ke-2, ke-4, ke-6, dll. dari daftar asli .
Wow! Mengapa saya tidak bisa memikirkan hal ini :) Anda hanya perlu menangani kasus di mana tidak ada pasangan absolut (entri ganjil)
Saurav Kumar
1
Bagi siapa pun yang mungkin bisa membantu, berikut adalah solusi untuk masalah yang serupa tetapi dengan pasangan yang tumpang tindih (bukan pasangan yang saling eksklusif).
Saya perlu membagi daftar dengan nomor dan memperbaikinya seperti ini.
l =[1,2,3,4,5,6]def divideByN(data, n):return[data[i*n :(i+1)*n]for i in range(len(data)//n)]>>>print(divideByN(l,2))[[1,2],[3,4],[5,6]]>>>print(divideByN(l,3))[[1,2,3],[4,5,6]]
Ada banyak cara untuk melakukan itu. Sebagai contoh:
lst =[1,2,3,4,5,6][(lst[i], lst[i+1])for i,_ in enumerate(lst[:-1])]>>>[(1,2),(2,3),(3,4),(4,5),(5,6)][i for i in zip(*[iter(lst)]*2)]>>>[(1,2),(3,4),(5,6)]
Berpikir bahwa ini adalah tempat yang baik untuk membagikan generalisasi saya tentang ini untuk n> 2, yang hanya merupakan jendela geser di atas iterable:
def sliding_window(iterable, n):
its =[ itertools.islice(iter, i,None)for i, iter
in enumerate(itertools.tee(iterable, n))]return itertools.izip(*its)
Judul pertanyaan ini menyesatkan, Anda tampaknya mencari pasangan yang berurutan, tetapi jika Anda ingin mengulangi semua pasangan yang memungkinkan, maka ini akan berhasil:
for i,v in enumerate(items[:-1]):for u in items[i+1:]:
Menggunakan pengetikan sehingga Anda dapat memverifikasi data menggunakan alat analisis statis mypy :
from typing importIterator,Any,Iterable,TypeVar,Tuple
T_ =TypeVar('T_')Pairs_Iter=Iterator[Tuple[T_, T_]]def legs(iterable:Iterator[T_])->Pairs_Iter:
begin = next(iterable)for end in iterable:yield begin, end
begin = end
ini berguna jika array Anda adalah dan Anda ingin mengulanginya secara berpasangan. Untuk beralih pada kembar tiga atau lebih, cukup ubah perintah langkah "rentang", misalnya:
[(a[i],a[i+1],a[i+2])for i in range(0,len(a),3)]
(Anda harus berurusan dengan nilai berlebih jika panjang dan langkah array Anda tidak cocok)
Di sini kita dapat memiliki alt_elemmetode yang sesuai untuk loop Anda.
def alt_elem(list, index=2):for i, elem in enumerate(list, start=1):ifnot i % index:yield tuple(list[i-index:i])
a = range(10)for index in[2,3,4]:print("With index: {0}".format(index))for i in alt_elem(a, index):print(i)
Keluaran:
With index:2(0,1)(2,3)(4,5)(6,7)(8,9)With index:3(0,1,2)(3,4,5)(6,7,8)With index:4(0,1,2,3)(4,5,6,7)
Catatan: Solusi di atas mungkin tidak efisien mengingat operasi yang dilakukan di func.
Jawaban:
Anda memerlukan
pairwise()
(ataugrouped()
) implementasi.Untuk Python 2:
Atau, lebih umum:
Di Python 3, Anda bisa mengganti
izip
denganzip()
fungsi bawaan, dan lepaskanimport
.Semua kredit untuk martineau untuk jawaban atas pertanyaan saya , saya telah menemukan ini sangat efisien karena hanya mengulangi sekali dalam daftar dan tidak membuat daftar yang tidak perlu dalam proses.
NB : Ini tidak harus bingung dengan
pairwise
resep dalamitertools
dokumentasi Python sendiri , yang menghasilkans -> (s0, s1), (s1, s2), (s2, s3), ...
, seperti yang ditunjukkan oleh @ lazyr dalam komentar.Tambahan kecil untuk mereka yang ingin melakukan pengecekan ketik dengan mypy pada Python 3:
sumber
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertools
fungsi resep dengan nama yang sama. Tentu saja milikmu lebih cepat ...izip_longest()
bukanizip()
. Misalnya:list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
->[(1, 2), (3, 0)]
. Semoga ini membantu.Anda perlu dua elemen, jadi
Dimana:
data[0::2]
artinya membuat subset kumpulan elemen itu(index % 2 == 0)
zip(x,y)
membuat koleksi tuple dari koleksi x dan y elemen indeks yang sama.sumber
for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
bukan salah satu dari mereka.sumber
zip
mengembalikanzip
objek dengan Python 3, yang tidak dapat disubkripsikan . Itu perlu dikonversi ke urutan (list
,,tuple
dll) terlebih dahulu, tetapi "tidak bekerja" adalah sedikit peregangan.Solusi sederhana.
sumber
((l[i], l[i+1])for i in range(0, len(l), 2))
untuk generator, dapat dengan mudah dimodifikasi untuk tupel yang lebih panjang.Sementara semua jawaban yang digunakan
zip
sudah benar, saya menemukan bahwa mengimplementasikan sendiri fungsionalitas itu mengarah ke kode yang lebih mudah dibaca:Bagian ini
it = iter(it)
memastikan bahwait
sebenarnya merupakan iterator, bukan hanya iterable. Jikait
sudah merupakan iterator, baris ini adalah no-op.Pemakaian:
sumber
it
hanya merupakan iterator dan bukan iterable. Solusi lain tampaknya bergantung pada kemungkinan untuk membuat dua iterator independen untuk urutan.for
loop di Python 3.5+ karena PEP 479 , yang menggantikan setiapStopIteration
peningkatan dalam generator dengan aRuntimeError
.Saya harap ini akan menjadi cara yang lebih elegan untuk melakukannya.
sumber
Jika Anda tertarik dengan kinerja, saya melakukan tolok ukur kecil (menggunakan perpustakaan saya
simple_benchmark
) untuk membandingkan kinerja solusi dan saya menyertakan fungsi dari salah satu paket saya:iteration_utilities.grouper
Jadi, jika Anda menginginkan solusi tercepat tanpa dependensi eksternal, Anda mungkin harus menggunakan pendekatan yang diberikan oleh Johnysweb (pada saat penulisan ini adalah jawaban yang paling banyak dipilih dan diterima).
Jika Anda tidak keberatan dengan ketergantungan tambahan maka
grouper
dariiteration_utilities
mungkin akan sedikit lebih cepat.Pikiran tambahan
Beberapa pendekatan memiliki beberapa batasan, yang belum dibahas di sini.
Misalnya beberapa solusi hanya bekerja untuk urutan (yaitu daftar, string, dll.), Misalnya solusi Margus / pyanon / taskinoor yang menggunakan pengindeksan sementara solusi lain bekerja pada setiap iterable (yaitu urutan dan generator, iterator) seperti Johnysweb / mic_e / solusi saya.
Kemudian Johnysweb juga memberikan solusi yang berfungsi untuk ukuran selain 2 sedangkan jawaban lainnya tidak (oke, the
iteration_utilities.grouper
juga memungkinkan pengaturan jumlah elemen ke "grup").Lalu ada juga pertanyaan tentang apa yang harus terjadi jika ada jumlah elemen ganjil dalam daftar. Haruskah barang yang tersisa dibubarkan? Haruskah daftar itu diisi dengan empuk agar ukurannya rata? Haruskah barang yang tersisa dikembalikan sebagai tunggal? Jawaban lainnya tidak membahas hal ini secara langsung, namun jika saya tidak mengabaikan apa pun mereka semua mengikuti pendekatan bahwa item yang tersisa harus diberhentikan (kecuali untuk jawaban taskinoors - yang benar-benar akan meningkatkan Pengecualian).
Dengan
grouper
Anda dapat memutuskan apa yang ingin Anda lakukan:sumber
Gunakan
zip
daniter
perintah bersama:Saya merasa solusi ini
iter
cukup elegan:Yang saya temukan di dokumentasi zip Python 3 .
Untuk menggeneralisasi ke
N
elemen sekaligus:sumber
zip(*iterable)
mengembalikan tuple dengan elemen berikutnya dari setiap iterable.l[::2]
mengembalikan elemen ke-1, ke-3, ke-5, dll. dari daftar: tanda titik dua menunjukkan bahwa irisan dimulai di awal karena tidak ada angka di belakangnya, tanda titik dua hanya diperlukan jika Anda menginginkan langkah 'pada irisan '(dalam hal ini 2).l[1::2]
melakukan hal yang sama tetapi dimulai pada elemen kedua daftar sehingga mengembalikan elemen ke-2, ke-4, ke-6, dll. dari daftar asli .sumber
[number::number]
kerja sintaksis. sangat membantu bagi mereka yang tidak sering menggunakan pythonDengan membongkar:
sumber
Bagi siapa pun yang mungkin bisa membantu, berikut adalah solusi untuk masalah yang serupa tetapi dengan pasangan yang tumpang tindih (bukan pasangan yang saling eksklusif).
Dari dokumentasi Python itertools :
Atau, lebih umum:
sumber
Anda dapat menggunakan paket more_itertools .
sumber
Saya perlu membagi daftar dengan nomor dan memperbaikinya seperti ini.
sumber
Ada banyak cara untuk melakukan itu. Sebagai contoh:
sumber
Berpikir bahwa ini adalah tempat yang baik untuk membagikan generalisasi saya tentang ini untuk n> 2, yang hanya merupakan jendela geser di atas iterable:
sumber
Judul pertanyaan ini menyesatkan, Anda tampaknya mencari pasangan yang berurutan, tetapi jika Anda ingin mengulangi semua pasangan yang memungkinkan, maka ini akan berhasil:
sumber
Menggunakan pengetikan sehingga Anda dapat memverifikasi data menggunakan alat analisis statis mypy :
sumber
Pendekatan sederhana:
ini berguna jika array Anda adalah dan Anda ingin mengulanginya secara berpasangan. Untuk beralih pada kembar tiga atau lebih, cukup ubah perintah langkah "rentang", misalnya:
(Anda harus berurusan dengan nilai berlebih jika panjang dan langkah array Anda tidak cocok)
sumber
Di sini kita dapat memiliki
alt_elem
metode yang sesuai untuk loop Anda.Keluaran:
Catatan: Solusi di atas mungkin tidak efisien mengingat operasi yang dilakukan di func.
sumber
sumber