कभी-कभी आपको किसी सीक्वेंस को मिलाकर एक ही वैल्यू बनानी होती है; कभी-कभी आप उस मिलाने के दौरान बनने वाली हर बीच की वैल्यू देखना चाहते हैं। Factor इनके लिए दो अलग टूल देता है: एक ही वैल्यू में समेटने के लिए reduce (sequences में), और चलते-चलते बनने वाले रूप के लिए math.statistics का संचयी समूह।
reduce: सामान्य फोल्डreduce ( seq init quot: ( prev elt -- next ) -- result )
reduce सीक्वेंस पर एक-एक एलिमेंट करके आगे बढ़ता है और अपने साथ एक चलती हुई वैल्यू (यानी एक्युमुलेटर) ले चलता है, जिसे वह दो आर्गुमेंट लेने वाले कोटेशन को सौंपता है। कोटेशन को चलता हुआ एक्युमुलेटर और अगला एलिमेंट मिलता है; वह स्टैक पर जो छोड़ता है, वही नया एक्युमुलेटर बन जाता है।
USING: math sequences ;
{ 1 2 3 4 } 0 [ + ] reduce . ! => 10
{ 1 2 3 4 } 1 [ * ] reduce . ! => 24
गैर-शून्य प्रारंभिक वैल्यू और अपना कॉम्बिनर, ये दो चीज़ें reduce के ऐसे हिस्से हैं जहाँ तक sum और product नहीं पहुँच सकते। जैसे, किसी सीक्वेंस की सबसे बड़ी वैल्यू, और अगर कोई वैल्यू उससे बड़ी न निकले तो एक डिफॉल्ट:
USING: math.order ;
{ 3 1 -4 5 -2 } 0 [ max ] reduce . ! => 5
{ -3 -1 -4 } 0 [ max ] reduce . ! => 0
प्रारंभिक वैल्यू 0 भी तुलना में शामिल रहती है: जब हर एलिमेंट हार जाता है, तब नतीजा यही 0 बनता है, इसलिए सारी वैल्यू ऋणात्मक होने पर भी सीक्वेंस कोई मनमानी सबसे छोटी वैल्यू नहीं, बल्कि 0 देता है।
कभी-कभी आपको सिर्फ अंतिम नतीजा नहीं, बल्कि हर बीच वाला नतीजा चाहिए होता है। math.statistics का संचयी समूह इनपुट जितनी ही लंबी एक सीक्वेंस लौटाता है, जिसमें हर स्थान पर उस स्थान तक के हिस्से को मिलाकर बना नतीजा होता है:
cum-sum ( seq -- newseq ) ! running total
cum-product ( seq -- newseq ) ! running product
cum-min ( seq -- newseq ) ! running minimum
cum-max ( seq -- newseq ) ! running maximum
USING: math.statistics ;
{ 3 1 4 1 5 9 2 6 } cum-sum . ! => { 3 4 8 9 14 23 25 31 }
{ 1 2 3 4 } cum-product . ! => { 1 2 6 24 }
{ 3 1 4 1 5 9 2 6 } cum-min . ! => { 3 1 1 1 1 1 1 1 }
{ 3 1 4 1 5 9 2 6 } cum-max . ! => { 3 3 4 4 5 9 9 9 }
एक काम का तरीका है संचयी रिडक्शन को एक के बाद एक जोड़ना: एक का आउटपुट खुद एक सीक्वेंस होता है, जिसे सीधे अगले में डाला जा सकता है। इसी वजह से "चलते हुए सारांश का चलता हुआ सारांश" दो शब्दों में लिखा जा सकता है। जोड़े कई तरह से बन सकते हैं। हर कदम किस चीज़ का सारांश बना रहा है, उसी हिसाब से उन्हें मिलाइए।
produce: सामान्य अनफोल्डreduce एक सीक्वेंस को समेटकर वैल्यू बना देता है। produce (sequences में) उल्टी दिशा में जाता है: यह बार-बार जाँच करके और कदम बढ़ाकर एक प्रारंभिक वैल्यू से सीक्वेंस बनाता है:
produce ( pred quot -- seq )
हर इटरेशन में पहले मौजूदा स्थिति पर pred चलता है। अगर वह सही लौटाता है, तो अगला एलिमेंट बनाने और स्थिति बदलने के लिए quot को कॉल किया जाता है। जब pred, f लौटाता है, तो इटरेशन रुक जाता है और जमा किए गए एलिमेंट लौटा दिए जाते हैं।
एक क्लासिक उदाहरण फिबोनाची सीक्वेंस है (हर संख्या पिछली दो संख्याओं का जोड़ होती है)। इसमें चलती हुई स्थिति जोड़ी (a, b) होती है। हर कदम b निकालता है, और फिर जोड़ी को (b, a + b) से बदल देता है:
USING: kernel math sequences ;
! Fibonacci numbers strictly below 100:
0 1 [ dup 100 < ] [ tuck + over ] produce 2nip .
! => { 1 1 2 3 5 8 13 21 34 55 89 }
चलती हुई स्थिति दो वैल्यू पर फैली होती है, इसलिए बॉडी जोड़ी को आगे बढ़ाने के लिए tuck (kernel में) का इस्तेमाल करती है, यानी वह तीन एलिमेंट वाला शफल जो सबसे ऊपर की वैल्यू को दूसरे के नीचे कॉपी कर देता है। अंत में 2nip (जो kernel में ही है और nip का दो-एलिमेंट वाला रूप है) सफाई कर देता है। इस कॉल को बाएँ से दाएँ पढ़िए:
[ dup 100 < ] जोड़ी के सबसे ऊपर रखी वैल्यू (यानी अगली निकलने वाली संख्या) को देखता है और तब तक चलता रहता है जब तक वह सीमा से नीचे है।[ tuck + over ] स्थिति को (b, a + b) तक बढ़ा देती है और b निकालती है। नतीजा यह होता है कि स्टैक पर तीन वैल्यू रह जाती हैं: नीचे नई जोड़ी और ऊपर निकाली गई संख्या।produce रुकने के बाद, पीछे बची दो वैल्यू (अंतिम जोड़ी) 2nip से हटा दी जाती हैं, और सिर्फ बनी हुई सीक्वेंस बचती है।produce ठीक reduce का उल्टा है: जहाँ reduce सीक्वेंस को समेटकर एक वैल्यू बना देता है, वहीं produce एक वैल्यू से सीक्वेंस खोलकर बनाता है।
आप लाइब्रेरियन हैं और सदस्यों के खातों का बहीखाता रखते हैं। हर हफ्ते आपकी मेज़ पर दो तरह का काम आता है:
हर हफ्ते आप बहीखाता मिलाते हैं: अनुरोध पूरे करने के बाद का अंतिम बैलेंस, लेन-देन से बनने वाला हर दिन का चलता बैलेंस, और जुर्माने बढ़ने के दौर को चिह्नित करने वाला चलता न्यूनतम स्तर।
protected-balance को परिभाषित कीजिए। यह एक opening बैलेंस और requests का एक ऐरे (धनात्मक या ऋणात्मक राशियाँ) लेता है और बारी-बारी हर अनुरोध पूरा करने के बाद अंतिम बैलेंस लौटाता है। जो निकासी बैलेंस को शून्य से नीचे ले जाए, वह केवल उपलब्ध राशि तक ही पूरी की जाती है, इसलिए चलता बैलेंस शून्य पर ही रुक जाता है।
100 { 50 -200 30 } protected-balance .
! => 30
500 { 100 -300 -250 } protected-balance .
! => 50
0 { -10 50 } protected-balance .
! => 50
running-balance को परिभाषित कीजिए। यह transactions का एक ऐरे लेता है और उतनी ही लंबाई का एक क्रम लौटाता है, जिसका i-वाँ एलिमेंट पहले i+1 लेन-देन के बाद का बैलेंस है (शून्य शुरुआती बैलेंस के सापेक्ष)।
{ 50 -30 -20 100 } running-balance .
! => { 50 20 0 100 }
least-balance-so-far को परिभाषित कीजिए। यह transactions का एक ऐरे लेता है और उतनी ही लंबाई का एक क्रम लौटाता है, जिसका i-वाँ एलिमेंट स्थान i तक (उस सहित) देखा गया सबसे कम चलता बैलेंस है। यही चलता न्यूनतम स्तर है, जो उन दिनों को पहचानने में काम आता है जब खाता जोखिम भरा लगता था।
{ 50 -30 -20 100 } least-balance-so-far .
! => { 50 20 0 0 }
{ 200 -50 -100 -200 } least-balance-so-far .
! => { 200 150 50 -150 }
पुस्तकालय जुर्माना-माफी कार्यक्रम चला रहा है: सदस्य का बकाया बैलेंस हर भुगतान अवधि में आधा कर दिया जाता है, जब तक वह माफी की सीमा तक या उससे नीचे न आ जाए। halve-until को परिभाषित कीजिए। यह एक principal और एक target लेता है और आधा की गई वैल्यू का क्रम लौटाता है (पूर्णांक विभाजन का उपयोग करके)। यह क्रम पहली बार आधा करने से शुरू होता है और तब तक चलता है जब तक चलती वैल्यू target से सख्ती से ऊपर बनी रहे। अंतिम बार निकाली गई वैल्यू वह पहली वैल्यू होगी जो target तक या उससे नीचे आ जाती है।
100 5 halve-until .
! => { 50 25 12 6 3 }
64 1 halve-until .
! => { 32 16 8 4 2 1 }
3 5 halve-until .
! => { }
Exercism पर साइन अप कीजिए और Factor को 47 कॉन्सेप्ट163 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।