Mendapatkan jumlah elemen dalam iterator dengan Python
142
Apakah ada cara yang efisien untuk mengetahui berapa banyak elemen yang ada dalam sebuah iterator dengan Python, secara umum, tanpa melakukan iterasi melalui setiap dan penghitungan?
Bergantian, def gen(): yield random.randint(0, 1)tidak terbatas, jadi Anda tidak akan pernah bisa menemukan panjang dengan mengulanginya.
tgray
1
Jadi, untuk memvalidasi yang sudah jelas: cara terbaik untuk mendapatkan "ukuran" dari sebuah iterator adalah dengan menghitung berapa kali Anda telah melalui iterasi, bukan? Dalam hal ini, apakah itu numIters = 0 ; while iterator: numIters +=1?
Mike Williamson
Menarik, jadi ini masalah terputus-putus
Akababa
241
Kode ini seharusnya berfungsi:
>>> iter = (i for i in range(50))
>>> sum(1for _ in iter)
50
Meskipun melakukan iterasi melalui setiap item dan menghitungnya, ini adalah cara tercepat untuk melakukannya.
Ini juga berfungsi jika iterator tidak memiliki item:
>>> sum(1for _ in range(0))
0
Tentu saja, ini berjalan selamanya untuk input tak terbatas, jadi ingatlah bahwa iterator bisa tak terbatas:
>>> sum(1for _ in itertools.count())
[nothing happens, forever]
Juga, ketahuilah bahwa iterator akan habis dengan melakukan ini, dan upaya lebih lanjut untuk menggunakannya tidak akan melihat elemen . Itu adalah konsekuensi yang tidak dapat dihindari dari desain iterator Python. Jika Anda ingin menyimpan elemen, Anda harus menyimpannya dalam daftar atau semacamnya.
Menurut saya seperti ini melakukan persis apa yang OP tidak ingin lakukan: iterasi melalui iterator dan menghitung.
Adam Crossland
37
Ini adalah cara hemat ruang untuk menghitung elemen secara iterable
Kapten Lepton
9
Meskipun ini bukan yang diinginkan OP, mengingat pertanyaannya tidak memiliki jawaban, jawaban ini menghindari pembuatan daftar, dan secara empiris lebih cepat dengan konstanta daripada metode pengurangan yang tercantum di atas.
Phillip Nordwall
5
Tidak dapat membantu: apakah _referensi ke Perl $_? :)
Alois Mahdal
17
@AloisMahdal Tidak. Ini adalah konvensional di Python untuk menggunakan nama _untuk variabel dummy yang nilainya tidak Anda pedulikan.
Taymon
69
Tidak, metode apa pun akan mengharuskan Anda menyelesaikan setiap hasil. Anda dapat melakukan
iter_length = len(list(iterable))
tetapi menjalankannya pada iterator tak terbatas tentu saja tidak akan pernah kembali. Ini juga akan menggunakan iterator dan perlu diatur ulang jika Anda ingin menggunakan isinya.
Memberi tahu kami masalah nyata yang Anda coba selesaikan dapat membantu kami menemukan cara yang lebih baik untuk mencapai tujuan Anda yang sebenarnya.
Sunting: Menggunakan list()akan membaca seluruh iterable ke dalam memori sekaligus, yang mungkin tidak diinginkan. Cara lain adalah melakukannya
sum(1for _ in iterable)
seperti yang diposting orang lain. Itu akan menghindari menyimpannya dalam memori.
masalahnya adalah saya membaca file dengan "pysam" yang memiliki jutaan entri. Pysam mengembalikan iterator. Untuk menghitung kuantitas tertentu, saya perlu tahu berapa banyak bacaan yang ada di file, tetapi saya tidak perlu membaca masing-masing ... itulah masalahnya.
6
Saya bukan pengguna pysam, tapi mungkin membaca file "malas". Masuk akal karena Anda tidak ingin memiliki file besar di memori. Jadi jika Anda pasti tahu tidak. catatan sebelum iterasi, satu-satunya cara adalah membuat dua iterator, dan menggunakan yang pertama untuk menghitung elemen dan yang kedua untuk membaca file. BTW. Jangan gunakan len(list(iterable))itu akan memuat semua data ke memori. Anda dapat menggunakan: reduce(lambda x, _: x+1, iterable, 0). Edit: Kode Zonda333 dengan jumlah juga bagus.
Tomasz Wysocki
1
@ user248237: mengapa Anda mengatakan Anda perlu mengetahui berapa banyak entri yang tersedia untuk menghitung kuantitas tertentu? Anda bisa membaca jumlah yang tetap dan mengelola kasing ketika jumlahnya kurang dari jumlah yang tetap (sangat mudah dilakukan menggunakan iterslice). Apakah ada alasan lain Anda harus membaca semua entri?
kriss
1
@Tomasz Perhatikan bahwa pengurangan tidak digunakan lagi, dan akan hilang dengan Python 3 dan yang lebih baru.
Wilduck
7
@ Wilduck: Ini belum hilang, baru saja dipindahkan kefunctools.reduce
Daenyth
34
Anda tidak bisa (kecuali tipe iterator tertentu mengimplementasikan beberapa metode spesifik yang memungkinkannya).
Umumnya, Anda dapat menghitung item iterator hanya dengan menggunakan iterator. Salah satu cara yang mungkin paling efisien:
import itertools
from collections import deque
defcount_iter_items(iterable):"""
Consume an iterable not reading it into memory; return the number of items.
"""
counter = itertools.count()
deque(itertools.izip(iterable, counter), maxlen=0) # (consume at C speed)return next(counter)
+1: dibandingkan dengan waktu sum(1 for _ in iterator), ini hampir dua kali lebih cepat.
augustomen
1
Lebih akurat untuk mengatakan bahwa ia menghabiskan iterable dengan membaca setiap item ke dalam memori dan segera membuangnya.
Rockallite
Penting untuk dicatat (yang saya abaikan) bahwa urutan argumen zippenting : jika Anda lulus zip(counter, iterable), Anda benar-benar akan mendapatkan 1 lebih banyak daripada jumlah yang dapat diulang!
Kye W Shi
jawaban yang sangat bagus. akan memberikan karunia di atasnya.
Reut Sharabani
18
Agak. Anda dapat memeriksa __length_hint__metodenya, tetapi diperingatkan bahwa (setidaknya hingga Python 3.4, seperti yang ditunjukkan oleh gsnedders dengan sangat membantu) ini adalah detail implementasi yang tidak terdokumentasi ( mengikuti pesan di utas ), yang dapat menghilang dengan baik atau memanggil setan hidung sebagai gantinya.
Jika tidak, tidak. Iterator hanyalah sebuah objek yang hanya mengekspos next()metode tersebut. Anda dapat memanggilnya sebanyak yang diperlukan dan mereka mungkin atau mungkin tidak akan menaikkannya StopIteration. Untungnya, perilaku ini sering kali transparan bagi pembuat kode. :)
Ini tidak lagi menjadi masalah, pada PEP 424 dan Python 3.4. __length_hint__sekarang didokumentasikan, tetapi ini adalah petunjuk dan tidak ada jaminan keakuratan.
gsnedders
13
Nah, bagi yang ingin mengetahui ringkasan pembahasan itu. Skor teratas akhir untuk menghitung ekspresi generator berdurasi 50 juta menggunakan:
Bisakah Anda menjelaskan mengapa len(list(gen))harus mengonsumsi lebih sedikit memori daripada pendekatan berdasarkan pengurangan? Yang pertama membuat yang baru listyang melibatkan alokasi memori sedangkan yang terakhir seharusnya tidak. Jadi saya berharap yang terakhir lebih hemat memori. Selain itu, konsumsi memori akan bergantung pada jenis elemen.
normanius
FYI: Saya dapat mereproduksi untuk python 3.6.8 (pada MacBookPro) bahwa metode 1 mengungguli metode lain dalam hal runtime (saya melewatkan metode 4).
Saya suka paket kardinalitas untuk ini, ini sangat ringan dan mencoba menggunakan implementasi tercepat yang tersedia tergantung pada iterable.
Pemakaian:
>>> import cardinality
>>> cardinality.count([1, 2, 3])
3>>> cardinality.count(i for i in range(500))
500>>> defgen():... yield'hello'... yield'world'>>> cardinality.count(gen())
2
count()Implementasi sebenarnya adalah sebagai berikut:
defcount(iterable):if hasattr(iterable, '__len__'):
return len(iterable)
d = collections.deque(enumerate(iterable, 1), maxlen=1)
return d[0][0] if d else0
Saya berasumsi Anda masih bisa mengulang iterator jika Anda menggunakan fungsi itu, ya?
jcollum
9
Sebuah iterator hanyalah sebuah objek yang memiliki penunjuk ke objek berikutnya untuk dibaca oleh semacam buffer atau aliran, ini seperti LinkedList di mana Anda tidak tahu berapa banyak hal yang Anda miliki sampai Anda mengulanginya. Iterator dimaksudkan agar efisien karena yang mereka lakukan hanyalah memberi tahu Anda apa yang berikutnya dengan referensi alih-alih menggunakan pengindeksan (tetapi seperti yang Anda lihat, Anda kehilangan kemampuan untuk melihat berapa banyak entri berikutnya).
Sebuah iterator tidak seperti daftar tertaut. Objek yang dikembalikan dari iterator tidak mengarah ke objek berikutnya, dan objek ini tidak (harus) disimpan dalam memori. Sebaliknya, itu dapat menghasilkan objek satu demi satu, berdasarkan logika batin apa pun (yang bisa, tetapi tidak harus, berdasarkan daftar yang disimpan).
Tom
1
@ Tom Saya menggunakan LinkedList sebagai contoh sebagian besar karena Anda tidak tahu berapa banyak yang Anda miliki karena Anda hanya tahu apa yang selanjutnya dalam arti (jika ada sesuatu). Saya minta maaf jika kata-kata saya tampak sedikit salah atau jika saya menyiratkan bahwa kata-kata itu sama.
Jesus Ramos
8
Mengenai pertanyaan awal Anda, jawabannya tetaplah tidak ada cara secara umum untuk mengetahui panjang sebuah iterator dengan Python.
Mengingat pertanyaan Anda dimotivasi oleh aplikasi pysam library, saya dapat memberikan jawaban yang lebih spesifik: Saya seorang kontributor PySAM dan jawaban definitifnya adalah bahwa file SAM / BAM tidak memberikan jumlah persis pembacaan yang selaras. Informasi ini juga tidak tersedia dengan mudah dari file indeks BAM. Yang terbaik yang bisa dilakukan adalah memperkirakan perkiraan jumlah perataan dengan menggunakan lokasi penunjuk file setelah membaca sejumlah perataan dan mengekstrapolasi berdasarkan ukuran total file. Ini cukup untuk menerapkan bilah kemajuan, tetapi bukan metode penghitungan penyelarasan dalam waktu yang konstan.
Ada dua cara untuk mendapatkan panjang "sesuatu" di komputer.
Cara pertama adalah menyimpan hitungan - ini memerlukan apa pun yang menyentuh file / data untuk memodifikasinya (atau kelas yang hanya mengekspos antarmuka - tetapi intinya sama).
Cara lain adalah mengulanginya dan menghitung seberapa besar ukurannya.
Merupakan praktik umum untuk meletakkan jenis informasi ini di header file, dan agar pysam memberi Anda akses ke ini. Saya tidak tahu formatnya, tetapi apakah Anda sudah memeriksa API?
Seperti yang dikatakan orang lain, Anda tidak dapat mengetahui panjangnya dari iterator.
Ini bertentangan dengan definisi iterator, yang merupakan penunjuk ke objek, ditambah informasi tentang cara menuju ke objek berikutnya.
Sebuah iterator tidak tahu berapa kali lagi iterator dapat melakukan iterasi hingga dihentikan. Ini bisa jadi tidak terbatas, jadi ketidakterbatasan mungkin jawaban Anda.
Tidak melanggar apa pun, dan tidak ada salahnya menerapkan pengetahuan sebelumnya saat menggunakan iterator. Ada miliaran iterator di sekitar, di mana Anda tahu, bahwa jumlah elemennya terbatas. Pikirkan tentang memfilter daftar, Anda dapat dengan mudah memberikan panjang maksimum, Anda tidak terlalu mengetahui berapa banyak elemen yang benar-benar sesuai dengan kondisi filter Anda. Ingin mengetahui jumlah elemen yang cocok adalah aplikasi yang valid, tidak melanggar ide misterius iterator.
Michael
0
Meskipun secara umum tidak mungkin untuk melakukan apa yang diminta, sering kali berguna untuk menghitung berapa banyak item yang diiterasi setelah diiterasi. Untuk itu, Anda bisa menggunakan jaraco.itertools.Counter atau sejenisnya. Berikut adalah contoh menggunakan Python 3 dan rwt untuk memuat paket.
$ rwt -q jaraco.itertools -- -q
>>> import jaraco.itertools
>>> items = jaraco.itertools.Counter(range(100))
>>> _ = list(counted)
>>> items.count
100>>> import random
>>> defgen(n):... for i in range(n):
... if random.randint(0, 1) == 0:
... yield i
... >>> items = jaraco.itertools.Counter(gen(100))
>>> _ = list(counted)
>>> items.count
48
Agaknya, Anda ingin menghitung jumlah item tanpa melakukan iterasi, sehingga iterator tidak habis, dan Anda menggunakannya lagi nanti. Ini dimungkinkan dengan copyataudeepcopy
import copy
defget_iter_len(iterator):return sum(1for _ in copy.copy(iterator))
###############################################
iterator = range(0, 10)
print(get_iter_len(iterator))
if len(tuple(iterator)) > 1:
print("Finding the length did not exhaust the iterator!")
else:
print("oh no! it's all gone")
Outputnya adalah " Finding the length did not exhaust the iterator!"
Secara opsional (dan tanpa pertimbangan), Anda bisa membayangi lenfungsi bawaan sebagai berikut:
import copy
deflen(obj, *, len=len):try:
if hasattr(obj, "__len__"):
r = len(obj)
elif hasattr(obj, "__next__"):
r = sum(1for _ in copy.copy(obj))
else:
r = len(obj)
finally:
passreturn r
Rentang bukanlah iterator. Ada beberapa jenis iterator yang dapat disalin, tetapi yang lain akan menyebabkan kode ini gagal dengan TypeError (misalnya generator), dan iterasi melalui iterator yang disalin dapat menyebabkan efek samping terjadi dua kali, atau menyebabkan kerusakan sewenang-wenang dalam kode yang, katakanlah, mengembalikan mapiterator yang mengharapkan panggilan fungsi yang dihasilkan hanya terjadi sekali.
Jawaban:
Tidak. Itu tidak mungkin.
Contoh:
import random def gen(n): for i in xrange(n): if random.randint(0, 1) == 0: yield i iterator = gen(10)
Panjangnya
iterator
tidak diketahui sampai Anda mengulanginya.sumber
def gen(): yield random.randint(0, 1)
tidak terbatas, jadi Anda tidak akan pernah bisa menemukan panjang dengan mengulanginya.numIters = 0 ; while iterator: numIters +=1
?Kode ini seharusnya berfungsi:
>>> iter = (i for i in range(50)) >>> sum(1 for _ in iter) 50
Meskipun melakukan iterasi melalui setiap item dan menghitungnya, ini adalah cara tercepat untuk melakukannya.
Ini juga berfungsi jika iterator tidak memiliki item:
>>> sum(1 for _ in range(0)) 0
Tentu saja, ini berjalan selamanya untuk input tak terbatas, jadi ingatlah bahwa iterator bisa tak terbatas:
>>> sum(1 for _ in itertools.count()) [nothing happens, forever]
Juga, ketahuilah bahwa iterator akan habis dengan melakukan ini, dan upaya lebih lanjut untuk menggunakannya tidak akan melihat elemen . Itu adalah konsekuensi yang tidak dapat dihindari dari desain iterator Python. Jika Anda ingin menyimpan elemen, Anda harus menyimpannya dalam daftar atau semacamnya.
sumber
_
referensi ke Perl$_
? :)_
untuk variabel dummy yang nilainya tidak Anda pedulikan.Tidak, metode apa pun akan mengharuskan Anda menyelesaikan setiap hasil. Anda dapat melakukan
tetapi menjalankannya pada iterator tak terbatas tentu saja tidak akan pernah kembali. Ini juga akan menggunakan iterator dan perlu diatur ulang jika Anda ingin menggunakan isinya.
Memberi tahu kami masalah nyata yang Anda coba selesaikan dapat membantu kami menemukan cara yang lebih baik untuk mencapai tujuan Anda yang sebenarnya.
Sunting: Menggunakan
list()
akan membaca seluruh iterable ke dalam memori sekaligus, yang mungkin tidak diinginkan. Cara lain adalah melakukannyasum(1 for _ in iterable)
seperti yang diposting orang lain. Itu akan menghindari menyimpannya dalam memori.
sumber
len(list(iterable))
itu akan memuat semua data ke memori. Anda dapat menggunakan:reduce(lambda x, _: x+1, iterable, 0)
. Edit: Kode Zonda333 dengan jumlah juga bagus.functools.reduce
Anda tidak bisa (kecuali tipe iterator tertentu mengimplementasikan beberapa metode spesifik yang memungkinkannya).
Umumnya, Anda dapat menghitung item iterator hanya dengan menggunakan iterator. Salah satu cara yang mungkin paling efisien:
import itertools from collections import deque def count_iter_items(iterable): """ Consume an iterable not reading it into memory; return the number of items. """ counter = itertools.count() deque(itertools.izip(iterable, counter), maxlen=0) # (consume at C speed) return next(counter)
(Untuk Python 3.x ganti
itertools.izip
denganzip
).sumber
sum(1 for _ in iterator)
, ini hampir dua kali lebih cepat.zip
penting : jika Anda luluszip(counter, iterable)
, Anda benar-benar akan mendapatkan 1 lebih banyak daripada jumlah yang dapat diulang!Agak. Anda dapat memeriksa
__length_hint__
metodenya, tetapi diperingatkan bahwa (setidaknya hingga Python 3.4, seperti yang ditunjukkan oleh gsnedders dengan sangat membantu) ini adalah detail implementasi yang tidak terdokumentasi ( mengikuti pesan di utas ), yang dapat menghilang dengan baik atau memanggil setan hidung sebagai gantinya.Jika tidak, tidak. Iterator hanyalah sebuah objek yang hanya mengekspos
next()
metode tersebut. Anda dapat memanggilnya sebanyak yang diperlukan dan mereka mungkin atau mungkin tidak akan menaikkannyaStopIteration
. Untungnya, perilaku ini sering kali transparan bagi pembuat kode. :)sumber
__length_hint__
sekarang didokumentasikan, tetapi ini adalah petunjuk dan tidak ada jaminan keakuratan.Nah, bagi yang ingin mengetahui ringkasan pembahasan itu. Skor teratas akhir untuk menghitung ekspresi generator berdurasi 50 juta menggunakan:
len(list(gen))
,len([_ for _ in gen])
,sum(1 for _ in gen),
ilen(gen)
(dari more_itertool ),reduce(lambda c, i: c + 1, gen, 0)
,diurutkan berdasarkan performa eksekusi (termasuk konsumsi memori), akan membuat Anda terkejut:
``
1: test_list.py:8: 0,492 KiB
gen = (i for i in data*1000); t0 = monotonic(); len(list(gen))
('list, sec', 1.9684218849870376)
2: test_list_compr.py:8: 0.867 KiB
gen = (i for i in data*1000); t0 = monotonic(); len([i for i in gen])
('list_compr, detik', 2.5885991149989422)
3: test_sum.py:8: 0,859 KiB
gen = (i for i in data*1000); t0 = monotonic(); sum(1 for i in gen); t1 = monotonic()
('jumlah, detik', 3.441088170016883)
4: more_itertools / more.py: 413: 1.266 KiB
d = deque(enumerate(iterable, 1), maxlen=1) test_ilen.py:10: 0.875 KiB gen = (i for i in data*1000); t0 = monotonic(); ilen(gen)
('ilen, detik', 9.812256851990242)
5: test_reduce.py:8: 0,859 KiB
gen = (i for i in data*1000); t0 = monotonic(); reduce(lambda counter, i: counter + 1, gen, 0)
('kurangi, detik', 13.436614598002052) ``
Jadi,
len(list(gen))
adalah yang paling sering dan lebih sedikit memori yang dikonsumsisumber
len(list(gen))
harus mengonsumsi lebih sedikit memori daripada pendekatan berdasarkan pengurangan? Yang pertama membuat yang barulist
yang melibatkan alokasi memori sedangkan yang terakhir seharusnya tidak. Jadi saya berharap yang terakhir lebih hemat memori. Selain itu, konsumsi memori akan bergantung pada jenis elemen.len(tuple(iterable))
bahkan bisa lebih efisien: artikel oleh Nelson MinarSaya suka paket kardinalitas untuk ini, ini sangat ringan dan mencoba menggunakan implementasi tercepat yang tersedia tergantung pada iterable.
Pemakaian:
>>> import cardinality >>> cardinality.count([1, 2, 3]) 3 >>> cardinality.count(i for i in range(500)) 500 >>> def gen(): ... yield 'hello' ... yield 'world' >>> cardinality.count(gen()) 2
count()
Implementasi sebenarnya adalah sebagai berikut:def count(iterable): if hasattr(iterable, '__len__'): return len(iterable) d = collections.deque(enumerate(iterable, 1), maxlen=1) return d[0][0] if d else 0
sumber
Sebuah iterator hanyalah sebuah objek yang memiliki penunjuk ke objek berikutnya untuk dibaca oleh semacam buffer atau aliran, ini seperti LinkedList di mana Anda tidak tahu berapa banyak hal yang Anda miliki sampai Anda mengulanginya. Iterator dimaksudkan agar efisien karena yang mereka lakukan hanyalah memberi tahu Anda apa yang berikutnya dengan referensi alih-alih menggunakan pengindeksan (tetapi seperti yang Anda lihat, Anda kehilangan kemampuan untuk melihat berapa banyak entri berikutnya).
sumber
Mengenai pertanyaan awal Anda, jawabannya tetaplah tidak ada cara secara umum untuk mengetahui panjang sebuah iterator dengan Python.
Mengingat pertanyaan Anda dimotivasi oleh aplikasi pysam library, saya dapat memberikan jawaban yang lebih spesifik: Saya seorang kontributor PySAM dan jawaban definitifnya adalah bahwa file SAM / BAM tidak memberikan jumlah persis pembacaan yang selaras. Informasi ini juga tidak tersedia dengan mudah dari file indeks BAM. Yang terbaik yang bisa dilakukan adalah memperkirakan perkiraan jumlah perataan dengan menggunakan lokasi penunjuk file setelah membaca sejumlah perataan dan mengekstrapolasi berdasarkan ukuran total file. Ini cukup untuk menerapkan bilah kemajuan, tetapi bukan metode penghitungan penyelarasan dalam waktu yang konstan.
sumber
Tolok ukur cepat:
import collections import itertools def count_iter_items(iterable): counter = itertools.count() collections.deque(itertools.izip(iterable, counter), maxlen=0) return next(counter) def count_lencheck(iterable): if hasattr(iterable, '__len__'): return len(iterable) d = collections.deque(enumerate(iterable, 1), maxlen=1) return d[0][0] if d else 0 def count_sum(iterable): return sum(1 for _ in iterable) iter = lambda y: (x for x in xrange(y)) %timeit count_iter_items(iter(1000)) %timeit count_lencheck(iter(1000)) %timeit count_sum(iter(1000))
Hasil:
10000 loops, best of 3: 37.2 µs per loop 10000 loops, best of 3: 47.6 µs per loop 10000 loops, best of 3: 61 µs per loop
Yaitu count_iter_items sederhana adalah cara untuk pergi.
Menyesuaikan ini untuk python3:
61.9 µs ± 275 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 74.4 µs ± 190 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 82.6 µs ± 164 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
sumber
Ada dua cara untuk mendapatkan panjang "sesuatu" di komputer.
Cara pertama adalah menyimpan hitungan - ini memerlukan apa pun yang menyentuh file / data untuk memodifikasinya (atau kelas yang hanya mengekspos antarmuka - tetapi intinya sama).
Cara lain adalah mengulanginya dan menghitung seberapa besar ukurannya.
sumber
Merupakan praktik umum untuk meletakkan jenis informasi ini di header file, dan agar pysam memberi Anda akses ke ini. Saya tidak tahu formatnya, tetapi apakah Anda sudah memeriksa API?
Seperti yang dikatakan orang lain, Anda tidak dapat mengetahui panjangnya dari iterator.
sumber
Ini bertentangan dengan definisi iterator, yang merupakan penunjuk ke objek, ditambah informasi tentang cara menuju ke objek berikutnya.
Sebuah iterator tidak tahu berapa kali lagi iterator dapat melakukan iterasi hingga dihentikan. Ini bisa jadi tidak terbatas, jadi ketidakterbatasan mungkin jawaban Anda.
sumber
Meskipun secara umum tidak mungkin untuk melakukan apa yang diminta, sering kali berguna untuk menghitung berapa banyak item yang diiterasi setelah diiterasi. Untuk itu, Anda bisa menggunakan jaraco.itertools.Counter atau sejenisnya. Berikut adalah contoh menggunakan Python 3 dan rwt untuk memuat paket.
$ rwt -q jaraco.itertools -- -q >>> import jaraco.itertools >>> items = jaraco.itertools.Counter(range(100)) >>> _ = list(counted) >>> items.count 100 >>> import random >>> def gen(n): ... for i in range(n): ... if random.randint(0, 1) == 0: ... yield i ... >>> items = jaraco.itertools.Counter(gen(100)) >>> _ = list(counted) >>> items.count 48
sumber
def count_iter(iter): sum = 0 for _ in iter: sum += 1 return sum
sumber
Agaknya, Anda ingin menghitung jumlah item tanpa melakukan iterasi, sehingga iterator tidak habis, dan Anda menggunakannya lagi nanti. Ini dimungkinkan dengan
copy
ataudeepcopy
import copy def get_iter_len(iterator): return sum(1 for _ in copy.copy(iterator)) ############################################### iterator = range(0, 10) print(get_iter_len(iterator)) if len(tuple(iterator)) > 1: print("Finding the length did not exhaust the iterator!") else: print("oh no! it's all gone")
Outputnya adalah "
Finding the length did not exhaust the iterator!
"Secara opsional (dan tanpa pertimbangan), Anda bisa membayangi
len
fungsi bawaan sebagai berikut:import copy def len(obj, *, len=len): try: if hasattr(obj, "__len__"): r = len(obj) elif hasattr(obj, "__next__"): r = sum(1 for _ in copy.copy(obj)) else: r = len(obj) finally: pass return r
sumber
map
iterator yang mengharapkan panggilan fungsi yang dihasilkan hanya terjadi sekali.