2011-06-07 12 views
5

तो मुझे लूप के भीतर स्टैक्ड किए गए कुछ फ़िल्टरों से कुछ दिलचस्प व्यवहार मिल रहा है। मैं एक प्रदर्शन के साथ शुरू करेंगे:स्टैक्ड फ़िल्टर() कॉल का अजीब व्यवहार

>>> x = range(100) 
>>> x = filter(lambda n: n % 2 == 0, x) 
>>> x = filter(lambda n: n % 3 == 0, x) 
>>> list(x) 
[0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96] 

यहाँ हम उम्मीद उत्पादन मिलता है। हमारे पास फ़िल्टर के भीतर एक फ़िल्टर के भीतर एक सीमा है, और फिल्टर की स्थिति ढेर हो रही है क्योंकि हम उन्हें चाहते हैं। अब मेरी समस्या आती है।
मैंने किसी संख्या के सापेक्ष प्राइम की गणना करने के लिए एक फ़ंक्शन लिखा है। यह इस तरह दिखता है:

def relative_primes(num): 
    '''Returns a list of relative primes, relative to the given number.''' 
    if num == 1: 
     return [] 
    elif is_prime(num): 
     return list(range(1, num)) 
    result = range(1, num) 
    for factor in prime_factors(num): 
     # Why aren't these filters stacking properly?       
     result = filter(lambda n: n % factor != 0, result) 
    return list(result) 

जो भी कारण के लिए, फिल्टर केवल() prime_factors से प्राप्त सूची में अंतिम कारक के लिए लागू किया जा रहा है। उदाहरण:

>>> prime_factors(30) 
[2, 3, 5] 
>>> relative_primes(30) 
[1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29] 

हम देख सकते हैं कि सूची में 2 या 3 के कोई गुणक हटा दिए गए थे। ये क्यों हो रहा है? उपर्युक्त उदाहरण क्यों काम करता है, लेकिन लूप के लिए फ़िल्टर नहीं करते हैं?

उत्तर

7

पायथन 3.x, filter() सूची के बजाय जनरेटर देता है। इस प्रकार, केवल factor का अंतिम मान उपयोग किया जाता है क्योंकि सभी तीन फ़िल्टर समान factor का उपयोग करते हैं। इसे काम करने के लिए आपको अपने लैम्ब्डा को थोड़ा संशोधित करने की आवश्यकता होगी।

result = filter(lambda n, factor=factor: n % factor != 0, result) 
+0

एक और संक्षिप्त विकल्प 'फ़िल्टर (कारक .__ rmod__, परिणाम) 'है, जो स्वीकार्य रूप से कोड को थोड़ा कम पठनीय बनाता है। –

1

इटरेटर का मूल्यांकन आलसी है। सभी फिल्टर केवल बयान

return list(result) 

उस समय तक में मूल्यांकन किया जाएगा, factor का मूल्य अंतिम प्रधानमंत्री कारक है। lambda फ़ंक्शंस में केवल स्थानीय नाम factor का संदर्भ होता है और निष्पादन के समय उस नाम पर जो भी मूल्य असाइन किया जाता है उसका उपयोग करेगा।

इसे ठीक करने का एक तरीका है प्रत्येक पुनरावृत्ति में एक सूची में कनवर्ट करना। आप सादगी के बजाय प्रदर्शन के बाद कर रहे हैं, तो आप भी कोशिश कर सकते हैं यह एक:

def relative_primes(n): 
    sieve = [1] * n 
    for i in range(2, n): 
     if not sieve[i] or n % i: 
      continue 
     sieve[::i] = [0] * (n // i) 
    return list(itertools.compress(range(n), sieve)) 
+0

यह। ठीक है, मुझे लगा कि इसे स्थानीय नाम 'कारक' के साथ करना पड़ सकता है। इसके लिए बहुत - बहुत धन्यवाद। इसके अलावा, मुझे पता है कि जीसीडी का उपयोग करके एक समाधान बेहतर है, लेकिन मेरे पास वास्तव में तेज़ होना है। मेरे पास एल्गोरिदम के कुछ संस्करण हैं। –

+0

सबकुछ काम करता है। इसके अलावा, मैंने अभी कुछ परीक्षण चलाए हैं, और मेरे एल्गोरिदम आपके द्वारा प्रस्तावित किए गए दो गुना तेज है, भले ही मैंने प्राइम नंबरों के लिए अतिरिक्त चेक जोड़ा हो। –

+0

@fosskers: आपको नहीं पता था कि आप प्रदर्शन के बाद हैं।एक और सरल कार्यान्वयन जोड़ा गया, जो भी तेज होना चाहिए। –

1

एक sidenote के रूप में, इस समारोह का एक बहुत आसान कार्यान्वयन

from fractions import gcd 
def relative_primes(n): 
    return [i for i in range(1, n) if gcd(n, i) == 1] 

संपादित है अगर मैं आपको सही ढंग से समझता हूं और दो पूर्णांक अपेक्षाकृत प्रमुख हैं यदि वे कोई सामान्य सकारात्मक कारक (divisors) साझा नहीं करते हैं। सबसे बड़ा आम विभाजक को इंगित करने के लिए नोटेशन का उपयोग करके, दो पूर्णांक ए और बी ar ई अपेक्षाकृत प्रधान अगर जीसीडी (ए, बी) == 1। तो आप निम्नलिखित तरीके से fractions मॉड्यूल का उपयोग कर सकते हैं।

from fractions import gcd 

num = 30 
relative_primes = filter(lambda x: gcd(x,num) == 1, xrange(1,num)) 
संबंधित मुद्दे