2017-07-13 11 views
7

पर विचार करें निम्नलिखित समारोह, जिसका उत्पादन माना जाता है iterables का एक अनुक्रम की कार्तीय उत्पाद होने के लिए:मेरा कार्टेशियन उत्पाद फ़ंक्शन क्यों काम नहीं करता है?

def cart(*iterables): 
    out = ((e,) for e in iterables[0]) 
    for iterable in iterables[1:]: 
     out = (e1 + (e2,) for e1 in out for e2 in iterable) 
    return out 

ठीक काम करता है जब जनरेटर comprehensions सूची comprehensions बदल दिए जाते हैं। यह भी काम करता है जब केवल 2 पुनरावृत्त होते हैं। लेकिन जब मैं

print(list(cart([1, 2, 3], 'ab', [4, 5]))) 

कोशिश मैं

[(1, 4, 4), (1, 4, 5), (1, 5, 4), (1, 5, 5), 
(2, 4, 4), (2, 4, 5), (2, 5, 4), (2, 5, 5), 
(3, 4, 4), (3, 4, 5), (3, 5, 4), (3, 5, 5)] 

क्यों इस और नहीं कार्तीय उत्पाद मिल सकता है?

+0

आप मध्यवर्ती परिणामों को स्मृति में संग्रहीत कर सकते हैं (जैसे सूची दृष्टिकोण जो काम करता है) और उस जीन के साथ उनके मूल्यांकन को स्थगित नहीं करते हैं। exp। जिनके मूल्य बार-बार पुनरावृत्तियों में बदल रहे हैं। –

+1

मुझे पता है कि यह प्रश्न पायथन में कार्टेशियन उत्पाद के लिए एल्गोरिदम लागू करने के बारे में है, लेकिन अगर कोई यहां पाइथन में कार्टेशियन उत्पाद को कैसे खोजता है, तो ध्यान दें कि यह पहले से ही ['itertools.product'] में लागू है (https://docs.python.org/3/library/itertools.html#itertools.product)। – jdehesa

उत्तर

8

आप जनरेटर एक्सप्रेशन बना रहे हैं, जो for iterable in iterables[1:]: लूप के अगले पुनरावृत्ति तक तब तक पुनरावृत्त नहीं होते हैं। वे बंद कर रहे हैं, जो रनटाइम पर देखे जाते हैं।

जनरेटर अभिव्यक्ति इस संबंध में अनिवार्य रूप से छोटे कार्य हैं, वे अपना स्वयं का दायरा बनाते हैं, और माता-पिता के दायरे से किसी भी नाम को काम करने के लिए बंद करने के रूप में माना जाना चाहिए। जब आप पुनरावृत्ति करते हैं तो 'फ़ंक्शन' निष्पादित किया जाता है, और केवल तब बंद होने की आवश्यकता होती है और वर्तमान वैरिएबल संदर्भित मान के लिए हल किया जाता है।

तो तुम इस तरह एक जनरेटर अभिव्यक्ति बनाएँ:

(e1 + (e2,) for e1 in out for e2 in iterable) 

जहां iterable एक बंद माता पिता गुंजाइश (अपने कार्य स्थानीय लोगों) से ली गई है। लेकिन जब आप लूप, पर अगली पुनरावृत्ति तक लुकअप नहीं किया जाता है तो iterable अनुक्रम अनुक्रम में अगला तत्व है।

तो [1, 2, 3], 'ab', [4, 5] की आपके इनपुट के लिए, आप एक जनरेटर अभिव्यक्ति जब iterable = 'ab' लेकिन समय आप वास्तव में पुनरावृति द्वारा, for पाश एक नया मान सौंपा है और अब iterable = [4, 5] है बनाएँ। जब आप आखिरकार अंतिम (जंजीर) जनरेटर पर फिर से शुरू होते हैं, तो iterable की गणना के लिए केवल अंतिम कार्यकाल ही होता है।

आप प्रभावी रूप से iterables[0], iterables[-1] * len(iterables) - 1 पर उत्पाद बना रहे हैं; iterables[1] से iterables[-2] पूरी तरह से छोड़ दिए गए हैं, सभी iterables[-1] द्वारा प्रतिस्थापित किए गए हैं।

आप एक जनरेटर समारोह का उपयोग बंद मुद्दे से बचने के लिए कर सकता है, iterable में गुजर एक स्थानीय करने के लिए बाध्य होने के लिए:

def gen_step(out, iterable): 
    for e1 in out: 
     for e2 in iterable: 
      yield e1 + (e2,) 

def cart(*iterables): 
    out = ((e,) for e in iterables[0]) 
    for iterable in iterables[1:]: 
     out = gen_step(out, iterable) 
    return out 

आप जनरेटर अभिव्यक्ति लौटने एक लैम्ब्डा के साथ एक ही कर सकता है:

def cart(*iterables): 
    out = ((e,) for e in iterables[0]) 
    for iterable in iterables[1:]: 
     out = (lambda it=iterable: (e1 + (e2,) for e1 in out for e2 in it))() 
    return out 
+0

विकल्प अभी भी आलसी हैं। अच्छा लगा। –

संबंधित मुद्दे