Apakah ada cara yang lebih ringkas, efisien atau hanya pythonic untuk melakukan hal berikut?
def product(list):
p = 1
for i in list:
p *= i
return p
EDIT:
Saya benar-benar menemukan bahwa ini sedikit lebih cepat daripada menggunakan operator.mul:
from operator import mul
# from functools import reduce # python3 compatibility
def with_lambda(list):
reduce(lambda x, y: x * y, list)
def without_lambda(list):
reduce(mul, list)
def forloop(list):
r = 1
for x in list:
r *= x
return r
import timeit
a = range(50)
b = range(1,50)#no zero
t = timeit.Timer("with_lambda(a)", "from __main__ import with_lambda,a")
print("with lambda:", t.timeit())
t = timeit.Timer("without_lambda(a)", "from __main__ import without_lambda,a")
print("without lambda:", t.timeit())
t = timeit.Timer("forloop(a)", "from __main__ import forloop,a")
print("for loop:", t.timeit())
t = timeit.Timer("with_lambda(b)", "from __main__ import with_lambda,b")
print("with lambda (no 0):", t.timeit())
t = timeit.Timer("without_lambda(b)", "from __main__ import without_lambda,b")
print("without lambda (no 0):", t.timeit())
t = timeit.Timer("forloop(b)", "from __main__ import forloop,b")
print("for loop (no 0):", t.timeit())
memberi saya
('with lambda:', 17.755449056625366)
('without lambda:', 8.2084708213806152)
('for loop:', 7.4836349487304688)
('with lambda (no 0):', 22.570688009262085)
('without lambda (no 0):', 12.472226858139038)
('for loop (no 0):', 11.04065990447998)
reduce
jawaban menaikkanTypeError
, sedangkanfor
jawaban loop kembali 1. Ini adalah bug dalamfor
jawaban loop (produk daftar kosong tidak lebih dari 1 daripada 17 atau 'armadillo').list
nama variabel ...+
untuk jenis daftar itu (juga untuk produk /*
). Sekarang saya menyadari bahwa Python diketik secara dinamis yang membuat segalanya lebih sulit, tetapi ini adalah masalah yang diselesaikan dalam bahasa waras dengan sistem tipe statis seperti Haskell. TetapiPython
hanya memungkinkansum
untuk bekerja pada angka, karenasum(['a', 'b'])
bahkan tidak berfungsi, jadi saya kembali mengatakan itu0
masuk akal untuksum
dan1
untuk produk.Jawaban:
Tanpa menggunakan lambda:
lebih baik dan lebih cepat. Dengan python 2.7.5
Dalam konfigurasi berikut:
Hasil dengan python 2.7.5
Hasil:
np.prod
adalah yang tercepat, jika Anda gunakannp.array
sebagai struktur data (18x untuk array kecil, 250x untuk array besar)dengan python 3.3.2:
Apakah python 3 lebih lambat?
sumber
int
adalah Python 2long
. Python 2 akan menggunakan "int" sampai meluap 32 bit; Python 3 akan menggunakan "long" dari awal. (2) Python 3.0 adalah "bukti konsep". Tingkatkan ke 3.1 ASAP!reduce
operator darifunctools
modul dengan Python 3. IEfrom functools import reduce
.sumber
operator.mul
cara yang lebih baik untuk melakukannya.reduce
)from functools import reduce
untuk membuatnya berfungsi dalam Python 3.jika Anda hanya memiliki nomor dalam daftar Anda:
EDIT : seperti yang ditunjukkan oleh @ off99555 ini tidak berfungsi untuk hasil bilangan bulat besar dalam hal ini mengembalikan hasil tipe
numpy.int64
sedangkan solusi Ian Clelland berdasarkanoperator.mul
danreduce
bekerja untuk hasil bilangan bulat besar karena ia kembalilong
.sumber
from numpy import prod; prod(list(range(5,101)))
dan hasilnya0
, dapatkah Anda mereproduksi hasil ini di Python 3?prod
mengembalikan hasil ketiknumpy.int64
dalam kasus ini dan Anda sudah mendapatkan overflow (nilai negatif sebenarnya) untukrange(5,23)
. Gunakan solusi @Ian Clelland berdasarkanoperator.mul
danreduce
untuk bilangan bulat besar (mengembalikanlong
dalam kasus ini yang tampaknya memiliki presisi sewenang-wenang).np.prod(np.arange(5.0,101.0))
atau mengubahnya menjadi float dengan melakukannp.prod(np.array(range(5,101)).astype(np.float64))
. Perhatikan bahwa NumPy menggunakannp.float64
alih-alihfloat
. Saya tidak tahu bedanya.Nah, jika Anda benar-benar ingin menjadikannya satu baris tanpa mengimpor apa pun yang dapat Anda lakukan:
Tapi jangan.
sumber
sumber
functools.reduce(..)
dalam python3Mulai
Python 3.8
,prod
fungsi telah dimasukkan kemath
modul di perpustakaan standar:yang mengembalikan produk dari suatu
start
nilai (default: 1) kali angka berulang:Perhatikan bahwa jika iterable kosong, ini akan menghasilkan
1
(ataustart
nilai jika disediakan).sumber
Saya ingat beberapa diskusi panjang tentang comp.lang.python (maaf, terlalu malas untuk menghasilkan pointer sekarang) yang menyimpulkan bahwa definisi asli Anda
product()
adalah yang paling Pythonic .Perhatikan bahwa proposal tersebut bukan untuk menulis loop untuk setiap kali Anda ingin melakukannya, tetapi untuk menulis fungsi satu kali (per jenis pengurangan) dan menyebutnya sesuai kebutuhan! Memanggil fungsi reduksi sangat Pythonic - ia bekerja dengan manis dengan ekspresi generator, dan sejak pengenalan yang sukses
sum()
, Python terus tumbuh semakin banyak fungsi pengurangan builtin -any()
danall()
merupakan tambahan terbaru ...Kesimpulan ini agak resmi -
reduce()
telah dihapus dari builtin Python 3.0, mengatakan:Lihat juga Nasib mengurangi () dalam Python 3000 untuk kutipan pendukung dari Guido (dan beberapa komentar yang kurang mendukung oleh Lispers yang membaca blog itu).
NB jika kebetulan Anda membutuhkan
product()
untuk kombinatorik, lihatmath.factorial()
(baru 2.6).sumber
Maksud dari jawaban ini adalah untuk memberikan perhitungan yang berguna dalam keadaan tertentu - yaitu ketika a) ada sejumlah besar nilai yang dikalikan sehingga produk akhir mungkin sangat besar atau sangat kecil, dan b) Anda tidak perlu Saya tidak begitu peduli dengan jawaban yang tepat, tetapi malah memiliki sejumlah urutan, dan ingin dapat memesannya berdasarkan produk masing-masing.
Jika Anda ingin melipatgandakan elemen daftar, di mana l adalah daftar, Anda dapat melakukan:
Sekarang, pendekatan itu tidak bisa dibaca
Jika Anda seorang ahli matematika yang tidak terbiasa dengan mengurangi () yang sebaliknya mungkin benar, tetapi saya tidak akan menyarankan menggunakannya dalam keadaan normal. Ini juga kurang dapat dibaca daripada fungsi product () yang disebutkan dalam pertanyaan (setidaknya untuk non-ahli matematika).
Namun, jika Anda pernah berada dalam situasi di mana Anda berisiko mengalami underflow atau overflow, seperti di
dan tujuan Anda adalah membandingkan produk-produk dari urutan yang berbeda daripada untuk mengetahui apa produk-produknya
adalah cara untuk pergi karena hampir tidak mungkin untuk memiliki masalah dunia nyata di mana Anda akan meluap atau melimpah dengan pendekatan ini. (Semakin besar hasil perhitungan itu, semakin besar produknya jika Anda bisa menghitungnya.)
sumber
Saya telah menguji berbagai solusi dengan perfplot (proyek kecil saya) dan menemukan itu
adalah jauh solusi tercepat (jika daftar tidak sangat singkat).
Kode untuk mereproduksi plot:
sumber
Saya terkejut tidak seorang pun telah menyarankan menggunakan
itertools.accumulate
denganoperator.mul
. Ini menghindari penggunaanreduce
, yang berbeda untuk Python 2 dan 3 (karenafunctools
impor diperlukan untuk Python 3), dan lebih lagi dianggap tidak pythonic oleh Guido van Rossum sendiri :Contoh:
sumber
Salah satu pilihan adalah menggunakan
numba
dan@jit
atau@njit
dekorator . Saya juga membuat satu atau dua perubahan kecil pada kode Anda (setidaknya dalam Python 3, "daftar" adalah kata kunci yang tidak boleh digunakan untuk nama variabel):Untuk keperluan pengaturan waktu, Anda perlu menjalankan satu kali untuk mengkompilasi fungsi terlebih dahulu menggunakan numba. Secara umum, fungsi akan dikompilasi pertama kali dipanggil, dan kemudian dipanggil dari memori setelah itu (lebih cepat).
Sekarang ketika Anda menjalankan kode Anda, itu akan berjalan dengan versi fungsi yang dikompilasi. Saya mengatur waktu mereka menggunakan notebook Jupyter dan
%timeit
fungsi sulap:Perhatikan bahwa pada mesin saya, menjalankan Python 3.5,
for
loop Python asli sebenarnya yang tercepat. Mungkin ada trik di sini untuk mengukur kinerja yang didekorasi dengan numba dengan notebook Jupyter dan%timeit
fungsi sulap. Saya tidak yakin pengaturan waktu di atas benar, jadi saya sarankan untuk mencobanya di sistem Anda dan melihat apakah numba memberi Anda peningkatan kinerja.sumber
Cara tercepat yang saya temukan adalah, menggunakan saat:
dan waktunya adalah:
sumber
Hasil Python 3 untuk tes OP: (terbaik 3 untuk masing-masing)
sumber
Ini juga berfungsi meskipun curang
sumber
print
dengan pengembalian. Juga, tidak perlu menyimpan nilai-nilai perantara dalam daftar, Anda hanya perlu menyimpanp
iterasi antarwe.