2013-02-23 12 views
11

के साथ समतुल्य नेस्टेड लूप संरचना इसकी बैटरी के माध्यम से पाइथन का सिक्यंतर वाक्यविन्यास पठनीय एक लाइनर में वर्बोज कोड लाइन को व्यक्त करने की अनुमति देता है। निम्न उदाहरणItertools

====================================================| 
for a in range(3):         | 
    for b in range(3):        | 
     for c in range(3):       | 
      print (a,b,c),       | 
- - - - - - - - - - - - - - - - - -| 
for e in product(range(3), repeat=3):    | 
    print e,          | 
====================================================| 
for a in range(3):         | 
    for b in range(a , 3):       | 
     for c in range(b , 3):      | 
      print (a,b,c),       | 
- - - - - - - - - - - - - - - - - -| 
for e in combinations_with_replacement(range(3), 3):| 
    print e,          | 
====================================================| 
for a in range(3):         | 
    for b in range(a + 1, 3):      | 
     for c in range(b + 1, 3):     | 
      print (a,b,c),       | 
- - - - - - - - - - - - - - - - - -| 
for e in combinations(range(3), 3):     | 
    print e,          | 
====================================================| 
for a in range(3):         | 
    for b in range(3):        | 
     for c in range(3):       | 
      if len(set([a,b,c])) == 3:    | 
       print (a,b,c),      | 
- - - - - - - - - - - - - - - - - -| 
for e in permutations(range(3)):     | 
    print e,          | 
====================================================| 
देर के

मैं एक गहरी नेस्ट निर्भर लूप मैं संक्षेप व्यक्त करने के लिए कोशिश कर रहा था के साथ समाप्त हो गया लेकिन

पाश की संरचना के रूप में

for a in A(): 
    for b in B(a): 
     for c in C(b): 
      foo(a,b,c) 

इस प्रकार होगा विफल रहा है पर विचार करें क्या ऐसी संरचना समकक्ष itertools नोटेशन में व्यक्त की जा सकती है?

+0

बस एक नोट। प्रोलॉग में यह अंतिम लूप इस प्रकार व्यक्त किया जाएगा: 'ए (ए), बी (ए, बी), सी (बी, सी)'। यदि आप लूप के साथ खेलना पसंद करते हैं, तो प्रोलॉग के साथ खेलें। – liori

+0

क्या आप सबसे ऊपर लूप के शरीर में 'ए',' बी' (इंटरमीडिएट वैल्यू) का उपयोग करते हैं? – jfs

+0

@ लिओरी: प्रोलॉग ने हमेशा मुझे लुभाया लेकिन कृत्रिम बुद्धि सीखने के लिए पर्याप्त बुद्धिमान नहीं था – Abhijit

उत्तर

4

वहाँ नहीं है, लेकिन आप एक बना सकते हैं:

def chainGang(steps, currentVars=None): 
    thisOne = steps[0] 
    if currentVars is None: 
     for item in thisOne(): 
      for gang in chainGang(steps[1:], [item]): 
       yield gang 
    elif len(steps) == 1:  
     for item in thisOne(currentVars[-1]): 
      yield currentVars + [item] 
    else: 
     for item in thisOne(currentVars[-1]): 
      for gang in chainGang(steps[1:], currentVars + [item]): 
       yield gang 

और फिर:

>>> outer = lambda: ["A", "B", "C", "D"] 
>>> middle = lambda letter: [letter, letter*2, letter*3] 
>>> inner = lambda s: range(len(s)+1) 
>>> for a in chainGang([outer, middle, inner]): 
...  print a 
[u'A', u'A', 0] 
[u'A', u'A', 1] 
[u'A', u'AA', 0] 
[u'A', u'AA', 1] 
[u'A', u'AA', 2] 
[u'A', u'AAA', 0] 
[u'A', u'AAA', 1] 
[u'A', u'AAA', 2] 
[u'A', u'AAA', 3] 
[u'B', u'B', 0] 
[u'B', u'B', 1] 
[u'B', u'BB', 0] 
[u'B', u'BB', 1] 
[u'B', u'BB', 2] 
[u'B', u'BBB', 0] 
[u'B', u'BBB', 1] 
[u'B', u'BBB', 2] 
[u'B', u'BBB', 3] 
[u'C', u'C', 0] 
[u'C', u'C', 1] 
[u'C', u'CC', 0] 
[u'C', u'CC', 1] 
[u'C', u'CC', 2] 
[u'C', u'CCC', 0] 
[u'C', u'CCC', 1] 
[u'C', u'CCC', 2] 
[u'C', u'CCC', 3] 
[u'D', u'D', 0] 
[u'D', u'D', 1] 
[u'D', u'DD', 0] 
[u'D', u'DD', 1] 
[u'D', u'DD', 2] 
[u'D', u'DDD', 0] 
[u'D', u'DDD', 1] 
[u'D', u'DDD', 2] 
[u'D', u'DDD', 3] 
5

कोई सटीक itertools समाधान है, लेकिन itertools कार्यों के एक साधारण संयोजन पर्याप्त होगा:

def chain_imap_accumulate(seq, f): 
    def acc_f(x): 
     for n in f(x[-1]): 
      yield x + (n,) 
    return chain.from_iterable(imap(acc_f, seq)) 

def accumulative_product(*generators): 
    head, tail = generators[0], generators[1:] 
    head = imap(tuple, head()) 
    return reduce(chain_imap_accumulate, tail, head) 

एक त्वरित परीक्षण। परिभाषाएं:

from itertools import chain, imap, izip 
chain_ = chain.from_iterable 

def A(): 
    yield 'A' 
    yield 'B' 

def B(x): 
    yield int(x, 16) 
    yield int(x, 16) + 1 

def C(x): 
    yield str(x) + 'Z' 
    yield str(x) + 'Y' 

और परिणाम:

>>> list(accumulative_product(A, B, C)) 
[('A', 10, '10Z'), ('A', 10, '10Y'), 
('A', 11, '11Z'), ('A', 11, '11Y'), 
('B', 11, '11Z'), ('B', 11, '11Y'), 
('B', 12, '12Z'), ('B', 12, '12Y')] 

लगभग सभी जटिलता एक त्वरित उपरोक्त कोड शो के "व्युत्पत्ति" के रूप में, आदानों के संचय से आता है। अंतिम (c) मूल्यों नेस्ट itertools निर्माणों का सिर्फ एक जोड़ी का उपयोग कर उत्पन्न किया जा सकता:

>>> list(chain_(imap(C, chain_(imap(B, (A())))))) 
['10Z', '10Y', '11Z', '11Y', '11Z', '11Y', '12Z', '12Y'] 

यह reduce साथ सामान्यीकृत किया जा सकता। reduce के साथ काम करने के लिए, chain_imap मानक imap तर्क आदेश का उपयोग नहीं कर सकते हैं। यह बदली किया जाना है:

>>> list(reduce(chain_imap, [B, C], A())) 
['10Z', '10Y', '11Z', '11Y', '11Z', '11Y', '12Z', '12Y'] 

अंतिम कार्य प्रारंभिक मान बढ़ते जा रहे हैं, ताकि आप a, b, और c की पहुंच है:

def chain_imap(seq, f): 
    return chain.from_iterable(imap(f, seq)) 

यह वही परिणाम देता है। यह सही करने के लिए सोचा था की एक बिट लेता है, लेकिन कार्यान्वयन काफी सरल है - हम सिर्फ एक समारोह है कि सभी इनपुट मानों लेकिन पिछले पर ध्यान नहीं देता में f कन्वर्ट करने के लिए है, और पूर्ण इनपुट करने के लिए नए मूल्यों को संलग्न कर देता है:

def chain_imap_accumulate(seq, f): 
    def acc_f(x): 
     for n in f(x[-1]): 
      yield x + (n,) 
    return chain.from_iterable(imap(acc_f, seq)) 

यह जरूरी है कि पहले आदानों tuples में लिपटे जा, तो हम नक्शा Atuple साथ:

>>> list(reduce(chain_imap_accumulate, [B, C], imap(tuple, A()))) 
[('A', 10, '10Z'), ('A', 10, '10Y'), 
('A', 11, '11Z'), ('A', 11, '11Y'), 
('B', 11, '11Z'), ('B', 11, '11Y'), 
('B', 12, '12Z'), ('B', 12, '12Y')] 

स्पष्टता के लिए ऊपर पुनर्लेखन, और यह जवाब परिणामों के शीर्ष पर कोड।

वैसे, chain_imap_accumulate को एक जीनक्स का उपयोग करके थोड़ी अधिक तेज़ी से फिर से लिखा जा सकता है।इसे बहुत ही कॉम्पैक्ट परिभाषा के लिए accumulative_product के छोटे संस्करण के साथ जोड़ा जा सकता है (यदि आप उस तरह की चीज़ में रूचि रखते हैं)। यह पूरी तरह से itertools निर्भरता को खत्म करने के लिए होता है:

def chain_map_accumulate(seq, f): 
    return (x + (n,) for x in seq for n in f(x[-1])) 

def accumulative_product2(*gens): 
    return reduce(chain_map_accumulate, gens[1:], (tuple(x) for x in gens[0]())) 
+1

इससे मेरा दिमाग दर्द होता है, लेकिन 3.3 के 'itertools.accumulate' का उपयोग करने का कोई तरीका है इसे सरल/जटिल बनाने के लिए इसका फ़ंक्शन पैरामीटर? – DSM

+0

मुझे लगता है कि आप सही हैं कि उस काम को करने का एक तरीका होना चाहिए। आप 'कम करें' के बजाय 'जमा' का उपयोग करने में सक्षम हो सकते हैं, और 'ए', 'बी', और' सी' मानों के अनुक्रम को जमा कर सकते हैं; लेकिन 'ए' मानों की संख्या' बी' मानों की संख्या से अलग होगी, जो 'सी' मानों की संख्या से अलग होगी। आपको तब यह समझना होगा कि मूल्यों को 'ए, बी, सी' टुपल्स के एक फ्लैट अनुक्रम में कैसे पुनर्वितरित करना है। चुनौती उस सुंदरता को करने के लिए होगी ... – senderle

+0

जमा करने से आप कुछ प्राप्त करेंगे -> '(' ए ',' बी '), ((10, 11), (11, 12)), ((' 10Z ',' 10Y '), (' 11Z ',' 11Y '), (' 11Z ',' 11Y '), (' 12Z ',' 12Y '))' मुझे यकीन नहीं है कि यह कोई क्लीनर होगा। – Moberg

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