रूबी में एक सरणी के माध्यम से पुनरावृति करने का "सही" तरीका क्या है?


341

PHP, अपने सभी मौसा के लिए, इस गिनती पर बहुत अच्छा है। किसी सरणी और हैश में कोई अंतर नहीं है (हो सकता है कि मैं अनुभवहीन हूं, लेकिन यह मुझे स्पष्ट रूप से सही लगता है), और इसके माध्यम से पुनरावृत्ति करने के लिए या तो बस करो

foreach (array/hash as $key => $value)

रूबी में इस तरह के काम करने के कई तरीके हैं:

array.length.times do |i|
end

array.each

array.each_index

for i in array

हैश अधिक मायने रखता है, क्योंकि मैं हमेशा उपयोग करता हूं

hash.each do |key, value|

मैं सरणियों के लिए ऐसा क्यों नहीं कर सकता? अगर मैं सिर्फ एक तरीका याद रखना चाहता हूं, तो मुझे लगता है कि मैं इसका उपयोग कर सकता हूं each_index(क्योंकि यह सूचकांक और मूल्य दोनों उपलब्ध कराता है), लेकिन यह array[index]सिर्फ करने के बजाय करने के लिए कष्टप्रद है value


ओह ठीक है, मैं भूल गया array.each_with_index। हालाँकि, यह एक बेकार है क्योंकि यह जाता है |value, key|और hash.eachजाता है |key, value|! क्या यह पागलपन नहीं है?


1
मुझे लगता है कि array#each_with_indexउपयोग करता है |value, key|क्योंकि विधि का नाम आदेश का अर्थ है, जबकि वाक्यविन्यास की hash#eachनकल करने के लिए इस्तेमाल किया गया आदेश hash[key] = value?
बेंजीनर

जवाबों:


560

यह सभी तत्वों के माध्यम से पुनरावृत्ति करेगा:

array = [1, 2, 3, 4, 5, 6]
array.each { |x| puts x }

प्रिंटों:

1
2
3
4
5
6

यह आपको मूल्य और सूचकांक देने वाले सभी तत्वों के माध्यम से पुन: व्यवस्थित करेगा:

array = ["A", "B", "C"]
array.each_with_index {|val, index| puts "#{val} => #{index}" }

प्रिंटों:

A => 0
B => 1
C => 2

मैं आपके प्रश्न से बिल्कुल आश्वस्त नहीं हूँ कि आप किसकी तलाश कर रहे हैं।


1
ऑफ़-टॉपिक I कठबोली में प्रत्येक_विथ_इंडेक्स को माणिक 1.9 में सरणी में पाया जाता है
CantGetANick

19
@CantGetANick: ऐरे क्लास में एन्यूमरेबल मॉड्यूल शामिल है जिसमें यह विधि है।
xuinkrbin।

88

मुझे लगता है कि कोई भी सही तरीका नहीं है। पुनरावृति के लिए कई अलग-अलग तरीके हैं, और प्रत्येक का अपना आला है।

  • each कई उपयोगों के लिए पर्याप्त है, क्योंकि मैं अक्सर अनुक्रमित के बारे में परवाह नहीं करता हूं।
  • each_ with _index हैश # प्रत्येक की तरह कार्य करता है - आपको मूल्य और सूचकांक मिलता है।
  • each_index- सिर्फ सूचकांक। मैं इसका इस्तेमाल अक्सर नहीं करता। "Length.times" के बराबर।
  • map जब आप एक सरणी को दूसरे में बदलना चाहते हैं, तो इसे पुन: उपयोग करने का एक और तरीका है।
  • select जब आप एक सबसेट का चयन करना चाहते हैं तो इसका उपयोग करने के लिए पुनरावृत्ति है।
  • inject रकम या उत्पाद तैयार करने या एकल परिणाम एकत्र करने के लिए उपयोगी है।

यह याद रखने के लिए बहुत कुछ लग सकता है, लेकिन चिंता न करें, आप उन सभी को जाने बिना प्राप्त कर सकते हैं। लेकिन जैसे-जैसे आप अलग-अलग तरीकों को सीखना और उपयोग करना शुरू करते हैं, आपका कोड क्लीनर और स्पष्ट हो जाएगा, और आप रूबी महारत के लिए अपने रास्ते पर होंगे।


बहुत बढ़िया जवाब! मैं #relect की तरह #reject और उपनाम की तरह रिवर्स का उल्लेख करना चाहूंगा।
एमिली तुई च

60

मैं यह नहीं कह रहा हूं कि Array-> |value,index|और Hash-> |key,value|पागल नहीं है (होरेस लोएब की टिप्पणी देखें), लेकिन मैं कह रहा हूं कि इस व्यवस्था की उम्मीद करने के लिए एक समझदार तरीका है।

जब मैं सरणियों के साथ काम कर रहा हूं, तो मैं सरणी में तत्वों पर ध्यान केंद्रित कर रहा हूं (सूचकांक नहीं, क्योंकि सूचकांक क्षणभंगुर है)। विधि प्रत्येक सूचकांक के साथ है, अर्थात प्रत्येक + सूचकांक, या प्रत्येक, सूचकांक |, या |value,index|। यह भी अनुक्रमणिका के साथ एक वैकल्पिक तर्क के रूप में देखा जा सकता है, उदाहरण के लिए | के बराबर है। मूल्य, सूचकांक = नील | जो मूल्य, सूचकांक के अनुरूप है।

जब मैं हैश के साथ काम कर रहा होता हूं, तो मैं अक्सर मूल्यों की तुलना में कुंजियों पर अधिक ध्यान केंद्रित करता हूं, और मैं आमतौर पर key => valueया तो उस क्रम में कुंजियों और मूल्यों के साथ काम कर रहा हूं hash[key] = value

यदि आप बत्तख-टाइपिंग चाहते हैं, तो ब्रेंट लॉन्गबोरो के रूप में या तो एक निर्धारित विधि का स्पष्ट रूप से एक परिभाषित विधि का उपयोग करें, या जैसा कि मैक्सकिंस ने दिखाया है।

रूबी प्रोग्रामर को सूट करने के लिए भाषा को समायोजित करने के बारे में है, न कि प्रोग्रामर को भाषा के अनुकूल होने के बारे में। यही कारण है कि बहुत सारे तरीके हैं। किसी चीज के बारे में सोचने के बहुत सारे तरीके हैं। रूबी में, आप सबसे करीबी चुनते हैं और बाकी कोड आमतौर पर बेहद करीने से और संक्षिप्त रूप से बाहर हो जाते हैं।

मूल प्रश्न के रूप में, "रूबी में एक सरणी के माध्यम से पुनरावृति करने के लिए" सही "तरीका क्या है?", ठीक है, मुझे लगता है कि कोर तरीका (यानी शक्तिशाली सिंटैक्टिक चीनी या वस्तु उन्मुख शक्ति के बिना) करना है:

for index in 0 ... array.size
  puts "array[#{index}] = #{array[index].inspect}"
end

लेकिन रूबी शक्तिशाली सिंटैक्टिक शुगर और ऑब्जेक्ट ओरिएंटेड पावर के बारे में है, लेकिन वैसे भी यहाँ हैश के बराबर है, और कुंजियों का आदेश दिया जा सकता है या नहीं:

for key in hash.keys.sort
  puts "hash[#{key.inspect}] = #{hash[key].inspect}"
end

तो, मेरा जवाब है, "रूबी में एक सरणी के माध्यम से पुनरावृति करने का" सही "तरीका आप (यानी प्रोग्रामर या प्रोग्रामिंग टीम) और परियोजना पर निर्भर करता है।" बेहतर रूबी प्रोग्रामर बेहतर विकल्प बनाता है (जिनमें से वाक्यगत शक्ति और / या जो वस्तु उन्मुख दृष्टिकोण है)। बेहतर रूबी प्रोग्रामर अधिक तरीकों की तलाश करना जारी रखता है।


अब, मैं एक और सवाल पूछना चाहता हूं, "रूबी पीछे की ओर एक सीमा के माध्यम से पुनरावृति करने का" सही "तरीका क्या है!" (यह सवाल है कि मैं इस पृष्ठ पर कैसे आया।)

यह करना अच्छा है (आगे के लिए):

(1..10).each{|i| puts "i=#{i}" }

लेकिन मैं ऐसा नहीं करना चाहता (पीछे की तरफ):

(1..10).to_a.reverse.each{|i| puts "i=#{i}" }

खैर, मुझे वास्तव में ऐसा करने में कोई आपत्ति नहीं है, लेकिन जब मैं पीछे की ओर जाना सिखा रहा हूं, तो मैं अपने छात्रों को एक अच्छा समरूपता दिखाना चाहता हूं (यानी कम से कम अंतर के साथ, उदाहरण के लिए केवल एक रिवर्स जोड़कर, या चरण -1, लेकिन बिना कुछ और संशोधित करना)। आप (समरूपता के लिए) कर सकते हैं:

(a=*1..10).each{|i| puts "i=#{i}" }

तथा

(a=*1..10).reverse.each{|i| puts "i=#{i}" }

जो मुझे बहुत पसंद नहीं है, लेकिन आप ऐसा नहीं कर सकते

(*1..10).each{|i| puts "i=#{i}" }
(*1..10).reverse.each{|i| puts "i=#{i}" }
#
(1..10).step(1){|i| puts "i=#{i}" }
(1..10).step(-1){|i| puts "i=#{i}" }
#
(1..10).each{|i| puts "i=#{i}" }
(10..1).each{|i| puts "i=#{i}" }   # I don't want this though.  It's dangerous

आप अंततः कर सकते हैं

class Range

  def each_reverse(&block)
    self.to_a.reverse.each(&block)
  end

end

लेकिन मैं वस्तु उन्मुख दृष्टिकोण (सिर्फ अभी तक) के बजाय शुद्ध रूबी सिखाना चाहता हूं। मैं पीछे की ओर चलना चाहूंगा:

  • एक सरणी बनाने के बिना (0..1000000000 पर विचार करें)
  • किसी भी रेंज के लिए काम करना
  • किसी भी अतिरिक्त वस्तु उन्मुख शक्ति (यानी कोई वर्ग संशोधन) का उपयोग किए बिना

मेरा मानना ​​है कि एक predविधि को परिभाषित किए बिना यह असंभव है , जिसका अर्थ है कि इसका उपयोग करने के लिए श्रेणी वर्ग को संशोधित करना। यदि आप ऐसा कर सकते हैं तो कृपया मुझे बताएं, अन्यथा असंभवता की पुष्टि की जाएगी, हालांकि यह निराशाजनक होगा। शायद रूबी 1.9 इसे संबोधित करता है।

(इसे पढ़ने में अपने समय के लिए धन्यवाद।)


5
1.upto(10) do |i| puts i endऔर 10.downto(1) do puts i endआप चाहते थे समरूपता देता है। उम्मीद है की वो मदद करदे। यकीन नहीं है कि यह तार और इस तरह के लिए काम करेगा।
सुरेन

(1..10) .to_a.sort {| x, y | y <=> x} .each {| i | डालता है "i = # {i}"} - रिवर्स अधिक धीमा है।
डेविडसन

आप कर सकते हैं [*1..10].each{|i| puts "i=#{i}" }
हौलेथ

19

जब आपको दोनों की जरूरत हो तो प्रत्येक_विथ_इंडेक्स का उपयोग करें।

ary.each_with_index { |val, idx| # ...

12

अन्य उत्तर ठीक हैं, लेकिन मैं एक अन्य परिधीय चीज़ को इंगित करना चाहता था: एरे का आदेश दिया जाता है, जबकि हैश 1.8 में नहीं हैं। (रूबी 1.9 में, हेड्स को कुंजियों के क्रम के अनुसार क्रमबद्ध किया जाता है।) इसलिए यह 1.9 से पहले समझ में नहीं आता है कि एरा के समान हैश / सीक्वेंस पर पुनरावृति करना, जिसका हमेशा एक निश्चित क्रम होता है। मुझे पता नहीं है कि PHP साहचर्य सरणियों के लिए डिफ़ॉल्ट क्रम क्या है (जाहिर है मेरा Google फू इतना मजबूत नहीं है कि यह पता लगा सके, या तो), लेकिन मुझे नहीं पता कि आप नियमित रूप से PHP सरणियों और PHP साहचर्य सरणियों पर कैसे विचार कर सकते हैं। इस संदर्भ में "समान" रहें, क्योंकि साहचर्य सरणियों के लिए आदेश अपरिभाषित लगता है।

जैसे, रूबी रास्ता मुझे अधिक स्पष्ट और सहज लगता है। :)


1
hashes और arrays एक ही बात है! ऑब्जेक्ट्स के लिए मैप पूर्णांक को एरेज़ करता है और ऑब्जेक्ट को मैप ऑब्जेक्ट को हैश करता है। सरणियाँ सिर्फ हैश के विशेष मामले हैं, नहीं?
टॉम लेहमन

1
जैसा कि मैंने कहा, एक सरणी एक ऑर्डर किया गया सेट है। एक मैपिंग (सामान्य ज्ञान में) अव्यवस्थित है। यदि आप कुंजी सेट को पूर्णांक (जैसे सरणियों के साथ) तक सीमित करते हैं, तो यह केवल इतना होता है कि कुंजी सेट का एक आदेश है। जेनेरिक मैपिंग (हैश / एसोसिएटिव एरे) में, चाबियों का ऑर्डर नहीं हो सकता है।
1

@ हॉर्स: हैशिंग और एरेज़ समान नहीं हैं। यदि एक दूसरे का एक विशेष अक्स है, तो वे समान नहीं हो सकते। लेकिन इससे भी बदतर, सरणियाँ एक विशेष प्रकार की हैश नहीं हैं, यह केवल उन्हें देखने का एक सार तरीका है। जैसा कि ब्रेंट ने ऊपर बताया है, हैश और एरे का उपयोग करते हुए एक कोड गंध का संकेत हो सकता है।
ज़ेन

9

एक ही चीज़ को लगातार सरणियों और हैश के साथ करने की कोशिश करना सिर्फ एक कोड गंध हो सकता है, लेकिन, मेरे जोखिम के कारण एक कोडोरस हाफ-बंदर-पैच के रूप में ब्रांडेड है, अगर आप लगातार व्यवहार की तलाश कर रहे हैं, तो यह चाल चलेगा। ?:

class Hash
    def each_pairwise
        self.each { | x, y |
            yield [x, y]
        }
    end
end

class Array
    def each_pairwise
        self.each_with_index { | x, y |
            yield [y, x]
        }
    end
end

["a","b","c"].each_pairwise { |x,y|
    puts "#{x} => #{y}"
}

{"a" => "Aardvark","b" => "Bogle","c" => "Catastrophe"}.each_pairwise { |x,y|
    puts "#{x} => #{y}"
}

7

यहां आपके प्रश्न में सूचीबद्ध चार विकल्प दिए गए हैं, जो नियंत्रण की स्वतंत्रता द्वारा व्यवस्थित हैं। आप अपनी जरूरत के आधार पर एक अलग का उपयोग करना चाह सकते हैं।

  1. बस मूल्यों के माध्यम से जाना:

    array.each
  2. बस सूचकांक के माध्यम से जाना:

    array.each_index
  3. सूचकांक + सूचकांक चर के माध्यम से जाओ:

    for i in array
  4. नियंत्रण लूप गणना + सूचकांक चर:

    array.length.times do | i |

5

मैं एक हैश का उपयोग करके एक मेनू ( कैम्पिंग और मार्कबाय में ) बनाने की कोशिश कर रहा था ।

प्रत्येक आइटम में 2 तत्व होते हैं: एक मेनू लेबल और एक URL , इसलिए एक हैश सही लगता था, लेकिन 'होम' के लिए '/ URL' हमेशा अंतिम दिखाई देता था (जैसा कि आप हैश की उम्मीद करेंगे), इसलिए मेनू आइटम गलत में दिखाई दिए गण।

each_sliceकाम के साथ एक सरणी का उपयोग करना :

['Home', '/', 'Page two', 'two', 'Test', 'test'].each_slice(2) do|label,link|
   li {a label, :href => link}
end

प्रत्येक मेनू आइटम के लिए अतिरिक्त मान जोड़ना (उदाहरण के लिए एक सीएसएस आईडी नाम) बस स्लाइस मान को बढ़ाने का मतलब है। तो, एक हैश की तरह लेकिन किसी भी संख्या में आइटम से युक्त समूहों के साथ। उत्तम।

तो यह सिर्फ एक समाधान में अनजाने में संकेत के लिए धन्यवाद कहना है!

स्पष्ट है, लेकिन बताते हुए: मैं सुझाव देता हूं कि यदि सरणी की लंबाई स्लाइस मान से विभाज्य है।


4

यदि आप enumerable mixin का उपयोग करते हैं (जैसा कि रेल करता है) आप सूचीबद्ध php स्निपेट के समान कुछ कर सकते हैं। बस प्रत्येक_सालिस विधि का उपयोग करें और हैश को समतल करें।

require 'enumerator' 

['a',1,'b',2].to_a.flatten.each_slice(2) {|x,y| puts "#{x} => #{y}" }

# is equivalent to...

{'a'=>1,'b'=>2}.to_a.flatten.each_slice(2) {|x,y| puts "#{x} => #{y}" }

कम बंदर-पेटिंग की आवश्यकता।

हालाँकि, जब आप पुनरावर्ती सरणी या सरणी मानों के साथ हैश करते हैं, तो यह समस्याएँ पैदा करता है। रूबी 1.9 में यह समस्या एक पैरामीटर के साथ समतल विधि से हल की जाती है जो निर्दिष्ट करती है कि पुनरावृत्ति कितनी गहरी है।

# Ruby 1.8
[1,2,[1,2,3]].flatten
=> [1,2,1,2,3]

# Ruby 1.9
[1,2,[1,2,3]].flatten(0)
=> [1,2,[1,2,3]]

इस प्रश्न के लिए कि क्या यह एक कोड गंध है, मुझे यकीन नहीं है। आमतौर पर जब मुझे पीछे की ओर झुकना पड़ता है तो मैं कुछ कदम पीछे कर देता हूं और महसूस करता हूं कि मैं समस्या पर हमला कर रहा हूं।


2

सही तरीका वह है जिसमें आप सबसे अधिक सहज महसूस करते हैं और जो आप करना चाहते हैं वही करते हैं। प्रोग्रामिंग में चीजें करने के लिए शायद ही कभी एक 'सही' तरीका होता है, अधिक बार चुनने के कई तरीके होते हैं।

यदि आप कुछ चीजों को करने के तरीके के साथ सहज हैं, तो बस इसे करें, जब तक कि यह काम नहीं करता है - तब यह बेहतर तरीका खोजने का समय है।


2

रूबी 2.1 में, प्रत्येक_विथ_इंडेक्स विधि को हटा दिया जाता है। इसके बजाय आप उपयोग कर सकते each_index

उदाहरण:

a = [ "a", "b", "c" ]
a.each_index {|x| print x, " -- " }

पैदा करता है:

0 -- 1 -- 2 --

4
यह सच नहीं है। जैसा कि स्वीकृत उत्तर की टिप्पणियों में कहा गया है, इसका कारण each_with_indexप्रलेखन में प्रकट नहीं होता है क्योंकि यह Enumerableमॉड्यूल द्वारा प्रदान किया गया है।
इज्जतहॉदज़

0

दोनों सरणियों और हैश के माध्यम से पुनरावृत्ति के लिए एक ही विधि का उपयोग करना समझ में आता है, उदाहरण के लिए नेस्टेड हैश-एंड-एरे संरचनाओं को अक्सर पार्सर्स से उत्पन्न किया जाता है, JSON फ़ाइलों को पढ़ने आदि से।

एक चतुर तरीका जो अभी तक उल्लेख नहीं किया गया है वह यह है कि यह मानक पुस्तकालय एक्सटेंशन के रूबी पहलुओं पुस्तकालय में कैसे किया जाता है । से यहाँ :

class Array

  # Iterate over index and value. The intention of this
  # method is to provide polymorphism with Hash.
  #
  def each_pair #:yield:
    each_with_index {|e, i| yield(i,e) }
  end

end

वहाँ पहले से ही Hash#each_pair, का एक उपनाम है Hash#each। तो इस पैच के बाद, हमारे पास भी है Array#each_pairऔर इसे दोनों जगह पर हैशिंग और एरे के माध्यम से पुन: उपयोग करने के लिए उपयोग कर सकते हैं। यह ओपी के देखे गए पागलपन को ठीक करता है Array#each_with_indexजिसकी तुलना में ब्लॉक तर्कों को उलट दिया गया है Hash#each। उदाहरण उपयोग:

my_array = ['Hello', 'World', '!']
my_array.each_pair { |key, value| pp "#{key}, #{value}" }

# result: 
"0, Hello"
"1, World"
"2, !"

my_hash = { '0' => 'Hello', '1' => 'World', '2' => '!' }
my_hash.each_pair { |key, value| pp "#{key}, #{value}" }

# result: 
"0, Hello"
"1, World"
"2, !"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.