किसी सूची का उत्पाद लौटाना


157

वहाँ एक और अधिक संक्षिप्त, कुशल या बस पायथोनिक तरीका निम्नलिखित है?

def product(list):
    p = 1
    for i in list:
        p *= i
    return p

संपादित करें:

मुझे वास्तव में पता चला है कि यह आपरेटर की तुलना में मामूली रूप से तेज है।

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())

मुझे देता है

('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)

3
इसमें दिए गए विकल्पों के बीच एक कार्यात्मक अंतर है कि एक खाली सूची के लिए reduceउत्तर एक उठाते हैं TypeError, जबकि forलूप उत्तर देता है। 1. यह लूप उत्तर में एक बग है for(खाली सूची का उत्पाद 17 से अधिक नहीं है 1) या 'आर्मडिलो')।
स्कॉट ग्रिफिथ्स

5
कृपया अपने चर के नाम के लिए बिल्ट-इन (जैसे सूची) के नामों का उपयोग करने से बचने की कोशिश करें।
मार्क बायर्स

2
पुराना उत्तर, लेकिन मुझे संपादित करने के लिए लुभाया जाता है, इसलिए यह listएक चर नाम के रूप में उपयोग नहीं करता है ...
beroe

13
एक खाली सूची का उत्पाद है 1. en.wikipedia.org/wiki/Empty_product
पॉल क्राउली

1
@ScottGriffiths मुझे निर्दिष्ट करना चाहिए कि मेरे पास संख्याओं की एक सूची है। और मैं कहूंगा कि एक खाली सूची का योग +उस प्रकार की सूची के लिए पहचान तत्व है (इसी तरह उत्पाद / के लिए *)। अब मुझे एहसास हुआ कि पायथन गतिशील रूप से टाइप किया गया है जो चीजों को कठिन बनाता है, लेकिन यह सेंस भाषाओं में हलस्केल जैसी स्थिर प्रकार प्रणालियों के साथ एक हल की गई समस्या है। लेकिन Pythonकेवल sumनंबर पर काम करने की अनुमति देता है, क्योंकि sum(['a', 'b'])यह भी काम नहीं करता है, इसलिए मैं फिर से कहता हूं कि उत्पाद के 0लिए sumऔर इसके 1लिए समझ में आता है ।
सेमीकॉलन

जवाबों:


169

लंबोदर का उपयोग किए बिना:

from operator import mul
reduce(mul, list, 1)

यह बेहतर और तेज है। अजगर 2.7.5 के साथ

from operator import mul
import numpy as np
import numexpr as ne
# from functools import reduce # python3 compatibility

a = range(1, 101)
%timeit reduce(lambda x, y: x * y, a)   # (1)
%timeit reduce(mul, a)                  # (2)
%timeit np.prod(a)                      # (3)
%timeit ne.evaluate("prod(a)")          # (4)

निम्नलिखित विन्यास में:

a = range(1, 101)  # A
a = np.array(a)    # B
a = np.arange(1, 1e4, dtype=int) #C
a = np.arange(1, 1e5, dtype=float) #D

अजगर 2.7.5 के साथ परिणाम

       | 1 | 2 | 3 | 4 |
------- + ----------- + ----------- + ----------- + ------ ----- +
 एक 20.8 .3s 13.3 .8s 22.6 µs 39.6 µs     
 बी 106 106s 95.3 92s 5.92 µs 26.1 95s
 सी 4.34 एमएस 3.51 एमएस 16.7 µ 38.9 1 एस
 डी 46.6 एमएस 38.5 एमएस 180 .6 एस 216 .5 एस

परिणाम: np.prodसबसे तेज़ एक है, यदि आप np.arrayडेटा संरचना (छोटे सरणी के लिए 18x, बड़े सरणी के लिए 250x) का उपयोग करते हैं

अजगर 3.3.2 के साथ:

       | 1 | 2 | 3 | 4 |
------- + ----------- + ----------- + ----------- + ------ ----- +
 एक 23.6 .3s 12.3 .6s 68.6 µs 84.9 µs     
 B 133 µs 107 7.s 7.42 µs 27.5 107s
 C 4.79 एमएस 3.74 एमएस 18.6 µ 40.9 74 एस
 D 48.4 ms 36.8 ms 187 µs 214 .8s

अजगर 3 धीमा है?


1
बहुत दिलचस्प है, धन्यवाद। किसी भी विचार क्यों अजगर 3 धीमी हो सकती है?
शमौन वाटकिंस

3
संभावित कारण: (1) पायथन 3 intपायथन 2 है long। पायथन 2 "इंट" का उपयोग करेगा जब तक कि यह 32 बिट्स से अधिक न हो जाए; पायथन 3 शुरू से "लंबे" का उपयोग करेगा। (२) पायथन ३.० "अवधारणा का प्रमाण" था। 3.1 ASAP में अपग्रेड करें!
जॉन मैकिन

1
अजगर 2.6: मैं एक अन्य मशीन पर एक ही परीक्षण पुन: किया है ( 'लैम्ब्डा के साथ:', 21.843887090682983) ( 'लैम्ब्डा के बिना:', 9.7096879482269287) अजगर 3.1: लैम्ब्डा के साथ: २४.७७१२१८०६१४ लैम्ब्डा के बिना: १०.७७५८३५०३७२
रुगेरो Turra

1
दोनों खाली सूची के साथ विफल।
बग

9
ध्यान दें कि आपको Python 3. IE में मॉड्यूल reduceसे ऑपरेटर को आयात करना होगा । functoolsfrom functools import reduce
क्रिस मुलर

50
reduce(lambda x, y: x * y, list, 1)

3
+1 लेकिन operator.mulइसे करने के बेहतर तरीके के बारे में @ वारो का जवाब देखें ।
क्रिस लुत्ज़

क्यों ऑपरेटर है। एक्स * वाई के लिए अधिमान्य है।
एडम ह्यूजेस

2
Oper.m.mul एक फ़ंक्शन है और इस प्रकार यह केवल x * y के लिए ही नहीं, बल्कि पूरे लैम्ब्डा एक्सप्रेशन (यानी पहला तर्क reduce) के लिए एक रिप्लेसमेंट होगा
जोहान्स चररा

6
आपको from functools import reduceपायथन 3 में काम करने के लिए एक आयात करना होगा। 3.
जीवनरक्षा

45

यदि आपकी सूची में बस नंबर हैं:

from numpy import prod
prod(list)

EDIT : जैसा कि @ off99555 द्वारा बताया गया है कि यह बड़े पूर्णांक परिणामों के लिए काम नहीं करता है, इस मामले में यह numpy.int64इयान क्लेलैंड के समाधान के आधार पर टाइप का परिणाम देता है operator.mulऔर reduceबड़े पूर्णांक परिणामों के लिए काम करता है क्योंकि यह वापस लौटता है long


अगर सूची छोटी है तो यह धीमी है
16

1
मैंने मूल्यांकन करने की कोशिश की from numpy import prod; prod(list(range(5,101)))और यह आउटपुट हुआ 0, क्या आप पायथन 3 पर इस परिणाम को पुन: पेश कर सकते हैं?
1199 बजे off99555

1
क्योंकि इस मामले में prodप्रकार का एक परिणाम देता है numpy.int64और आपको पहले से ही एक अतिप्रवाह (वास्तव में एक नकारात्मक मूल्य) मिलता है range(5,23)। बड़े operator.mulऔर reduceपूर्णांक के आधार पर @ इयान क्लेलैंड के समाधान का उपयोग करें (यह longइस मामले में एक रिटर्न देता है जो मनमाना सटीक लगता है)।
आंद्रे होल्जनर

@ off99555 दो समाधान: या तो फ्लोट टाइप सूची के साथ शुरू करें np.prod(np.arange(5.0,101.0))या इसे करके फ्लोट में परिवर्तित करें np.prod(np.array(range(5,101)).astype(np.float64))। ध्यान दें कि np.float64इसके बजाय NumPy का उपयोग करता है float। मैं अंतर नहीं जानता।
लकड़ी

22

यदि आप वास्तव में कुछ भी कर सकते हैं, तो आप इसे बिना किसी आयात के एक पंक्ति बनाना चाहते थे

eval('*'.join(str(item) for item in list))

लेकिन नहीं।


संक्षेप में पाइथोनिक
जितिन

कुछ भी आयात किए बिना सोल के लिए ty!
जॉन डी

18
import operator
reduce(operator.mul, list, 1)

1
क्या अंतिम तर्क (1) वास्तव में आवश्यक है?
रग्गरो तुर्रा

10
यदि सूची खाली हो सकती है, तो अंतिम तर्क आवश्यक है, अन्यथा यह TypeError अपवाद को फेंक देगा। बेशक, कभी-कभी एक अपवाद वह होगा जो आप चाहते हैं।
डेव किर्बी

2
मेरे लिए यह उस तर्क के बिना 0 देता है, इसलिए आप खाली उत्पाद सम्मेलन को लागू करने के लिए भी आवश्यक समझ सकते हैं।
बग

या functools.reduce(..)में python3
आंद्रे Holzner

18

प्रारंभ Python 3.8, मानक पुस्तकालय में मॉड्यूल में एक prodफ़ंक्शन शामिल किया गया है math:

math.prod (iterable, *, start = 1)

जो startमानों का उत्पाद लौटाता है (डिफ़ॉल्ट: 1) संख्याओं के चलने योग्य समय:

import math

math.prod([2, 3, 4]) # 24

ध्यान दें कि यदि चलने योग्य खाली है, तो यह उत्पादन करेगा 1(या startयदि प्रदान किया गया है तो मूल्य)।


15

मुझे comp.lang.python पर कुछ लंबी चर्चाएँ याद हैं (क्षमा करें, अब संकेत पैदा करने के लिए बहुत आलसी) जो यह निष्कर्ष निकालता है कि आपकी मूल product()परिभाषा सबसे अधिक पायथन है

ध्यान दें कि प्रस्ताव हर बार जब आप इसे करना चाहते हैं, तो लूप के लिए लिखना नहीं है, लेकिन एक बार एक फ़ंक्शन लिखने के लिए (प्रति प्रकार की कमी) और इसे आवश्यकतानुसार कॉल करें! कटौती कार्यों को कॉल करना बहुत पाइथोनिक है - यह जनरेटर के भावों के साथ मधुरता से काम करता है, और जब से इसकी शुरूआत हुई है sum(), तब से पायथन अधिक से अधिक बिलियन कटौती कार्यों को बढ़ा रहा है - any()औरall() नवीनतम परिवर्धन हैं ...

यह निष्कर्ष थोथा आधिकारिक है - reduce()इसे पायथन 3.0 में बिल्डरों से हटा दिया गया था , कहा:

"उपयोग करें functools.reduce()यदि आपको वास्तव में इसकी आवश्यकता है, हालांकि, 99 प्रतिशत समय लूप के लिए स्पष्ट है और अधिक पठनीय है।"

पायथन 3000 में भी कम करने का भाग्य देखेंगुइडो से एक सहायक उद्धरण (और लिस्पर्स द्वारा कुछ कम सहायक टिप्पणियां जो उस ब्लॉग को पढ़ती हैं) के लिए ।

PS अगर संयोग से आपको product()कॉम्बिनेटरिक्स की आवश्यकता है, तो देखें math.factorial()(नया 2.6)।


2
पायथन समुदाय में प्रचलित मनोदशाओं के एक सटीक (मेरे ज्ञान के सर्वश्रेष्ठ) खाते के लिए +1 - जबकि मैं निश्चित रूप से इस मामले में प्रचलित मनोदशाओं के खिलाफ जाना पसंद करता हूं, यह उनके लिए जानना सबसे अच्छा है कि वे वैसे भी क्या हैं। इसके अलावा, मैं LtU से असमर्थित लिस्पर्स के बारे में थोड़ा पसंद करता हूं (मैं उनमें से एक होगा, मुझे लगता है)। :-)
मिचेल मार्कीज

7

इस उत्तर का आशय एक ऐसी गणना प्रदान करना है जो कुछ विशेष परिस्थितियों में उपयोगी हो - अर्थात् जब (क) बड़ी संख्या में ऐसे गुणकों का गुणा किया जाता है जैसे कि अंतिम उत्पाद बहुत बड़ा या बहुत छोटा हो सकता है, और b) आप डॉन ' टी वास्तव में सटीक उत्तर के बारे में परवाह है, लेकिन इसके बजाय कई क्रम हैं, और प्रत्येक के उत्पाद के आधार पर उन्हें ऑर्डर करने में सक्षम होना चाहते हैं।

यदि आप किसी सूची के तत्वों को गुणा करना चाहते हैं, जहाँ l सूची है, तो आप कर सकते हैं:

import math
math.exp(sum(map(math.log, l)))

अब, यह दृष्टिकोण उतना पठनीय नहीं है

from operator import mul
reduce(mul, list)

यदि आप एक गणितज्ञ हैं जो कम () के साथ परिचित नहीं हैं, तो विपरीत सच हो सकता है, लेकिन मैं इसे सामान्य परिस्थितियों में उपयोग करने की सलाह नहीं दूंगा। यह प्रश्न में वर्णित उत्पाद () फ़ंक्शन (कम से कम गैर-गणितज्ञों) की तुलना में कम पठनीय है।

हालाँकि, यदि आप कभी ऐसी स्थिति में होते हैं, जहाँ आप अंतर्प्रवाह या अतिप्रवाह का जोखिम उठाते हैं, जैसे कि

>>> reduce(mul, [10.]*309)
inf

और आपका उद्देश्य विभिन्न अनुक्रमों के उत्पादों की तुलना करने के बजाय यह जानना है कि उत्पाद क्या हैं

>>> sum(map(math.log, [10.]*309))
711.49879373515785

जाने का रास्ता है क्योंकि यह वास्तव में एक वास्तविक दुनिया की समस्या है जिसमें आप इस दृष्टिकोण के साथ अतिप्रवाह या कम प्रवाहित होना असंभव है। (उस गणना का परिणाम जितना बड़ा होगा, उतना बड़ा उत्पाद होगा यदि आप इसकी गणना कर सकते हैं।)


1
यह चतुर है, लेकिन यदि आपके पास कोई नकारात्मक या शून्य मान है तो विफल रहता है। : /
एलेक्स मीबुर्ग

7

मैंने परफ्लोट (मेरी एक छोटी परियोजना) के साथ विभिन्न समाधानों का परीक्षण किया है और पाया है कि

numpy.prod(lst)

है अब तक का सबसे तेजी से समाधान (यदि सूची बहुत ही कम नहीं है)।

यहां छवि विवरण दर्ज करें


प्लॉट को फिर से तैयार करने के लिए कोड:

import perfplot
import numpy

import math
from operator import mul
from functools import reduce

from itertools import accumulate


def reduce_lambda(lst):
    return reduce(lambda x, y: x * y, lst)


def reduce_mul(lst):
    return reduce(mul, lst)


def forloop(lst):
    r = 1
    for x in lst:
        r *= x
    return r


def numpy_prod(lst):
    return numpy.prod(lst)


def math_prod(lst):
    return math.prod(lst)


def itertools_accumulate(lst):
    for value in accumulate(lst, mul):
        pass
    return value


perfplot.show(
    setup=numpy.random.rand,
    kernels=[reduce_lambda, reduce_mul, forloop, numpy_prod, itertools_accumulate, math_prod],
    n_range=[2 ** k for k in range(15)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)

2

मैं कोई एक का उपयोग का सुझाव दिया है हैरान हूँ itertools.accumulateके साथ operator.mul। यह प्रयोग करने से बचा जाता है reduce, जो कि पायथन 2 और 3 के लिए अलग है ( functoolsपायथन 3 के लिए आवश्यक आयात के कारण ), और इसके अलावा स्वयं Guido van Rossum द्वारा संयुक्त राष्ट्र-पाइथोनिक माना जाता है :

from itertools import accumulate
from operator import mul

def prod(lst):
    for value in accumulate(lst, mul):
        pass
    return value

उदाहरण:

prod([1,5,4,3,5,6])
# 1800

1

एक विकल्प का उपयोग करना है numbaऔर @jitया @njitडेकोरेटर । मैंने आपके कोड में एक या दो छोटे ट्वीक्स बनाए (कम से कम पायथन 3 में, "सूची" एक कीवर्ड है जिसे एक चर नाम के लिए उपयोग नहीं किया जाना चाहिए):

@njit
def njit_product(lst):
    p = lst[0]  # first element
    for i in lst[1:]:  # loop over remaining elements
        p *= i
    return p

समय के उद्देश्यों के लिए, आपको पहले सुंबा का उपयोग करके फ़ंक्शन को संकलित करने के लिए एक बार चलाने की आवश्यकता है। सामान्य तौर पर, फ़ंक्शन को पहली बार संकलित करने के लिए संकलित किया जाएगा, और फिर उसके बाद मेमोरी से कॉल किया जाएगा (तेज)।

njit_product([1, 2])  # execute once to compile

अब जब आप अपना कोड निष्पादित करते हैं, तो यह फ़ंक्शन के संकलित संस्करण के साथ चलेगा। मैंने उन्हें एक ज्यूपिटर नोटबुक और %timeitमैजिक फ़ंक्शन का उपयोग करके समय दिया :

product(b)  # yours
# 32.7 µs ± 510 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

njit_product(b)
# 92.9 µs ± 392 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

ध्यान दें कि मेरी मशीन पर, पायथन 3.5 चला रहा है, देशी पायथन forलूप वास्तव में सबसे तेज था। जुपिटर नोटबुक्स और %timeitमैजिक फंक्शन के साथ सुंबा-डेकोरेटेड परफॉरमेंस को मापने की बात आने पर यहाँ एक ट्रिक हो सकती है । मुझे यकीन नहीं है कि ऊपर दिए गए समय सही हैं, इसलिए मैं इसे आपके सिस्टम पर आज़माने की सलाह देता हूं और यह देखता हूं कि सुब्बा आपको एक प्रदर्शन को बढ़ावा देता है या नहीं।


0

सबसे तेज़ तरीका मुझे मिला, जबकि उपयोग करते हुए:

mysetup = '''
import numpy as np
from find_intervals import return_intersections 
'''

# code snippet whose execution time is to be measured
mycode = '''

x = [4,5,6,7,8,9,10]
prod = 1
i = 0
while True:
    prod = prod * x[i]
    i = i + 1
    if i == len(x):
        break
'''

# timeit statement for while:
print("using while : ",
timeit.timeit(setup=mysetup,
              stmt=mycode))

# timeit statement for mul:
print("using mul : ",
    timeit.timeit('from functools import reduce;
    from operator import mul;
    c = reduce(mul, [4,5,6,7,8,9,10])'))

# timeit statement for mul:
print("using lambda : ",      
    timeit.timeit('from functools import reduce;
    from operator import mul;
    c = reduce(lambda x, y: x * y, [4,5,6,7,8,9,10])'))

और समय हैं:

>>> using while : 0.8887967770060641

>>> using mul : 2.0838719510065857

>>> using lambda : 2.4227715369997895

यह सूची की छोटी लंबाई के कारण होने की संभावना है, कुछ और प्रयोग की आवश्यकता है
craymichael

0

ओपी के परीक्षणों के लिए पायथन 3 परिणाम: (प्रत्येक के लिए सर्वश्रेष्ठ 3)

with lambda: 18.978000981995137
without lambda: 8.110567473006085
for loop: 10.795806062000338
with lambda (no 0): 26.612515013999655
without lambda (no 0): 14.704098362999503
for loop (no 0): 14.93075215499266

-4

यह भी काम करता है हालांकि यह धोखा है

def factorial(n):
    x=[]
    if n <= 1:
        return 1
    else:
        for i in range(1,n+1): 
            p*=i
            x.append(p)
        print x[n-1]    

मैंने इंडेंटेशन तय कर लिया है, लेकिन मुझे लगता है कि आपको अंतिम printको रिटर्न के साथ बदलना चाहिए । इसके अलावा, एक सूची में मध्यवर्ती मूल्यों को संग्रहीत करने की कोई आवश्यकता नहीं है, आपको बस pbetweens पुनरावृत्तियों को संग्रहीत करने की आवश्यकता है ।
बोपप्रेह
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.