रूबी मैजिक के एक और एपिसोड का समय आ गया है! इस बार, हम रूबी की सबसे जादुई विशेषताओं में से एक को देखेंगे, जो रूबी की गणना योग्य कक्षाओं जैसे Array
के साथ काम करते समय आपके द्वारा उपयोग की जाने वाली अधिकांश विधियों को प्रदान करती है। , Hash
और Range
. इस प्रक्रिया में, हम सीखेंगे कि आप गणना योग्य वस्तुओं के साथ क्या कर सकते हैं, गणना कैसे काम करती है, और किसी एक विधि को लागू करके किसी वस्तु को गणना योग्य कैसे बनाया जाए।
Enumerable
, #each
और Enumerator
गणना वस्तुओं पर ट्रैवर्सिंग को संदर्भित करता है। रूबी में, हम किसी वस्तु को गणना योग्य कहते हैं जब यह वस्तुओं के एक सेट और उनमें से प्रत्येक पर लूप करने की विधि का वर्णन करता है।
बिल्ट-इन एन्यूमरेबल्स Enumerable
. को शामिल करके अपनी एन्यूमरेशन फीचर्स प्राप्त करते हैं मॉड्यूल, जो #include?
. जैसी विधियां प्रदान करता है , #count
, #map
, #select
और #uniq
, दूसरों के बीच में। सरणियों और हैश से जुड़ी अधिकांश विधियाँ वास्तव में इन कक्षाओं में स्वयं लागू नहीं की जाती हैं, वे शामिल हैं।
नोट :कुछ तरीके, जैसे #count
और #take
Array
. पर वर्ग, हैं Enumerable
. से सरणी का उपयोग करने के बजाय विशेष रूप से सरणियों के लिए लागू किया गया मापांक। यह आमतौर पर ऑपरेशन को तेज करने के लिए किया जाता है।
Enumerable
मॉड्यूल #each
. नामक विधि पर निर्भर करता है , जिसे इसमें शामिल किसी भी वर्ग में लागू करने की आवश्यकता है। जब किसी सरणी पर ब्लॉक के साथ कॉल किया जाता है, तो #each
विधि प्रत्येक सरणी के तत्वों के लिए ब्लॉक निष्पादित करेगी।
irb> [1,2,3].each { |i| puts "* #{i}" }
* 1
* 2
* 3
=> [1,2,3]
अगर हम #each
. को कॉल करते हैं एक सरणी पर विधि बिना इसके प्रत्येक तत्व के लिए निष्पादित करने के लिए एक ब्लॉक पास करना, हमें Enumerator
. का एक उदाहरण प्राप्त होगा ।
irb> [1,2,3].each
=> #<Enumerator: [1, 2, 3]:each>
Enumerator
. के उदाहरण वर्णन करें कि किसी वस्तु पर पुनरावृति कैसे करें। एन्यूमरेटर मैन्युअल रूप से ऑब्जेक्ट और चेन एन्यूमरेशन पर पुनरावृति करते हैं।
irb> %w(dog cat mouse).each.with_index { |a, i| puts "#{a} is at position #{i}" }
dog is at position 0
cat is at position 1
mouse is at position 2
=> ["dog", "cat", "mouse"]
#with_index
विधि इस बात का एक अच्छा उदाहरण है कि परिवर्तित गणक कैसे कार्य करते हैं। इस उदाहरण में, #each
एक गणक वापस करने के लिए सरणी पर कहा जाता है। फिर, #with_index
प्रत्येक तत्व के सूचकांक को प्रिंट करने की अनुमति देने के लिए प्रत्येक सरणी के तत्वों में सूचकांक जोड़ने के लिए कहा जाता है।
वस्तुओं को गणना योग्य बनाना
हुड के तहत, #max
. जैसी विधियां , #map
और #take
#each
. पर भरोसा करें कार्य करने की विधि।
def max
max = nil
each do |item|
if !max || item > max
max = item
end
end
max
end
आंतरिक रूप से, Enumerable
के तरीकों में सी कार्यान्वयन है, लेकिन ऊपर दिया गया उदाहरण मोटे तौर पर दिखाता है कि कैसे #max
काम करता है। #each
. का उपयोग करके सभी मानों पर लूप करने और उच्चतम को याद रखने के लिए, यह अधिकतम मान लौटाता है।
def map(&block)
new_list = []
each do |item|
new_list << block.call(item)
end
new_list
end
#map
फ़ंक्शन प्रत्येक आइटम के साथ पारित ब्लॉक को कॉल करता है और परिणाम को सभी मानों पर लूप करने के बाद वापस आने के लिए एक नई सूची में डालता है।
चूंकि Enumerable
. में सभी विधियां #each
का उपयोग करें कुछ हद तक, कस्टम वर्ग को गणना योग्य बनाने में हमारा पहला कदम #each
. को लागू करना है विधि।
#each
को लागू करना
#each
. को लागू करके फ़ंक्शन और Enumerable
. सहित एक वर्ग में मॉड्यूल, यह गणना योग्य हो जाता है और #min
. जैसी विधियों को प्राप्त करता है , #take
और #inject
मुफ्त में।
हालांकि अधिकांश स्थितियों में किसी मौजूदा ऑब्जेक्ट पर वापस गिरने की अनुमति होती है जैसे कि एक सरणी और #each
. को कॉल करना उस पर विधि, आइए एक उदाहरण देखें जहां हमें इसे खरोंच से खुद लिखना है। इस उदाहरण में, हम #each
. लागू करेंगे लिंक की गई सूची . पर इसे गणनीय बनाने के लिए।
लिंक्ड सूचियां:सरणियों के बिना सूचियां
एक लिंक्ड सूची डेटा तत्वों का एक संग्रह है, जिसमें प्रत्येक तत्व अगले की ओर इशारा करता है। सूची में प्रत्येक तत्व के दो मान हैं, जिसका नाम सिर . है और पूंछ . सिर तत्व का मान रखता है, और पूंछ बाकी सूची की एक कड़ी है।
[42, [12, [73, nil]]
तीन मूल्यों (42, 12 और 73) के साथ एक लिंक्ड सूची के लिए, पहले तत्व का सिर 42 है, और पूंछ दूसरे तत्व की एक कड़ी है। दूसरे तत्व का शीर्ष 12 है, और पूंछ में तीसरा तत्व है। तीसरे तत्व का शीर्ष 73 है, और पूंछ nil
है , जो सूची के अंत को इंगित करता है।
रूबी में, एक लिंक की गई सूची को एक वर्ग का उपयोग करके बनाया जा सकता है जिसमें @head
. नामक दो आवृत्ति चर होते हैं और @tail
।
class LinkedList
def initialize(head, tail = nil)
@head, @tail = head, tail
end
def <<(item)
LinkedList.new(item, self)
end
def inspect
[@head, @tail].inspect
end
end
#<<
विधि का उपयोग सूची में नए मान जोड़ने के लिए किया जाता है, जो एक नई सूची को सिर के रूप में पारित मान के साथ, और पिछली सूची को पूंछ के रूप में लौटाकर काम करता है।
इस उदाहरण में, #inspect
विधि जोड़ दी जाती है ताकि हम सूची में देख सकें कि इसमें कौन से तत्व शामिल हैं।
irb> LinkedList.new(73) << 12 << 42
=> [42, [12, [73, nil]]]
अब जब हमारे पास एक लिंक की गई सूची है, तो आइए #each
. को लागू करें इस पर। #each
फ़ंक्शन एक ब्लॉक लेता है और ऑब्जेक्ट में प्रत्येक मान के लिए इसे निष्पादित करता है। हमारी लिंक्ड सूची पर इसे लागू करते समय, हम सूची के @head
पर पास किए गए ब्लॉक को कॉल करके अपने लाभ के लिए सूची की पुनरावर्ती प्रकृति का उपयोग कर सकते हैं। , और #each
. पर कॉल कर रहे हैं @tail
. पर , अगर यह मौजूद है।
class LinkedList
def initialize(head, tail = nil)
@head, @tail = head, tail
end
def <<(item)
LinkedList.new(item, self)
end
def inspect
[@head, @tail].inspect
end
def each(&block)
block.call(@head)
@tail.each(&block) if @tail
end
end
कॉल करते समय #each
हमारी लिंक्ड सूची के एक उदाहरण पर, यह वर्तमान @head
. के साथ पारित ब्लॉक को कॉल करता है . फिर, यह लिंक की गई सूची में से प्रत्येक को @tail
. में कॉल करता है जब तक कि टेल nil
न हो ।
irb> list = LinkedList.new(73) << 12 << 42
=> [42, [12, [73, nil]]]
irb> list.each { |item| puts item }
42
12
73
=> nil
अब जबकि हमारी लिंक की गई सूची #each
. का जवाब देती है , हम include Enumberable
हमारी सूची को गणनीय बनाने के लिए।
class LinkedList
include Enumerable
def initialize(head, tail = nil)
@head, @tail = head, tail
end
def <<(item)
LinkedList.new(item, self)
end
def inspect
[@head, @tail].inspect
end
def each(&block)
block.call(@head)
@tail.each(&block) if @tail
end
end
irb> list = LinkedList.new(73) << 12 << 42
=> [42, [12, [73, nil]]]
irb> list.count
=> 3
irb> list.max
=> 73
irb> list.map { |item| item * item }
=> [1764, 144, 5329]
irb> list.select(&:even?)
=> [42, 12]
वापसी Enumerator
उदाहरण
अब हम अपनी लिंक की गई सूची में सभी मानों पर लूप कर सकते हैं, लेकिन हम अभी तक गणना योग्य कार्यों को श्रृंखलाबद्ध नहीं कर सकते हैं। ऐसा करने के लिए, हमें एक Enumerator
return लौटाना होगा उदाहरण के लिए जब हमारा #each
फ़ंक्शन को बिना ब्लॉक के कॉल किया जाता है।
class LinkedList
include Enumerable
def initialize(head, tail = nil)
@head, @tail = head, tail
end
def <<(item)
LinkedList.new(item, self)
end
def inspect
[@head, @tail].inspect
end
def each(&block)
if block_given?
block.call(@head)
@tail.each(&block) if @tail
else
to_enum(:each)
end
end
end
किसी ऑब्जेक्ट को एन्यूमरेटर में लपेटने के लिए, हम #to_enum
. को कॉल करते हैं उस पर विधि। हम :each
. पास करते हैं , क्योंकि यह वह तरीका है जिसका उपयोग गणक को आंतरिक रूप से करना चाहिए।
अब, हमारे #each
. पर कॉल करें ब्लॉक के बिना विधि हमें श्रृंखला गणना करने की अनुमति देगी।
irb> list = LinkedList.new(73) << 12 << 42
=> [42, [12, [73, nil]]]
irb> list.each
=> #<Enumerator: [42, [12, [73, nil]]]:each>
irb> list.map.with_index.to_h
=> {42=>0, 12=>1, 73=>2}
कोड की नौ पंक्तियाँ और एक शामिल
#each
. को लागू करके Enumerable
. का उपयोग करके मॉड्यूल और वापसी Enumerator
अपने आप से वस्तुओं, हम कोड की नौ पंक्तियों और एक शामिल जोड़कर अपनी लिंक की गई सूची को सुपरचार्ज करने में सक्षम थे।
यह रूबी में एन्यूमरेबल्स के हमारे अवलोकन को समाप्त करता है। हमें यह जानना अच्छा लगेगा कि आपने इस लेख के बारे में क्या सोचा, या यदि आपके कोई प्रश्न हैं। हम हमेशा जांच करने और समझाने के लिए विषयों की तलाश में रहते हैं, इसलिए यदि रूबी में कुछ जादुई है जिसके बारे में आप पढ़ना चाहते हैं, तो हमें अभी @AppSignal पर बताने में संकोच न करें!