क्या कोई कारण है कि हम माणिक में "रिवर्स रेंज" पर पुनरावृति नहीं कर सकते हैं?


104

मैंने एक सीमा का उपयोग करके पीछे की ओर पुनरावृति करने की कोशिश की और each:

(4..0).each do |i|
  puts i
end
==> 4..0

0..4संख्या के माध्यम से Iteration । दूसरी सीमा पर r = 4..0ठीक लगता है r.first == 4,, r.last == 0

यह मुझे अजीब लगता है कि ऊपर का निर्माण अपेक्षित परिणाम नहीं देता है। उसका क्या कारण है? जब यह व्यवहार उचित हो तो क्या स्थितियाँ हैं?


मैं न केवल इस पुनरावृत्ति को महसूस करने के तरीके में दिलचस्पी रखता हूं, जो स्पष्ट रूप से समर्थित नहीं है, लेकिन इसके बजाय यह सीमा 4..0 ही वापस आती है। भाषा डिजाइनरों का इरादा क्या था? क्यों, किन स्थितियों में यह अच्छा है? मैंने अन्य रूबी निर्माणों में भी ऐसा ही व्यवहार देखा और उपयोगी होने पर भी यह साफ नहीं है।
पंद्रह

1
सम्मेलन द्वारा ही सीमा वापस की जाती है। चूंकि .eachकथन कुछ भी संशोधित नहीं किया था, इसलिए लौटने के लिए कोई गणना "परिणाम" नहीं है। जब यह मामला होता है, तो रूबी आमतौर पर सफलता और nilत्रुटि पर मूल वस्तु वापस करती है । इससे आप किसी ifस्टेटमेंट पर शर्तों जैसी अभिव्यक्तियों का उपयोग कर सकते हैं ।
बटा २३'१० को ०:

जवाबों:


99

एक सीमा बस यह है कि: कुछ इसकी शुरुआत और अंत से परिभाषित होता है, इसकी सामग्री से नहीं। एक सीमा पर "निष्क्रिय करना" वास्तव में एक सामान्य मामले में समझ में नहीं आता है। उदाहरण के लिए, दो तिथियों द्वारा निर्मित सीमा पर आप "पुनरावृति" कैसे करेंगे। क्या आप दिन के समय पुनरावृति करेंगे? महीने से? साल से? सप्ताह से? यह अच्छी तरह से परिभाषित नहीं है। IMO, यह तथ्य कि इसे आगे की सीमाओं के लिए अनुमति दी जाती है, केवल एक सुविधा विधि के रूप में देखा जाना चाहिए।

यदि आप उस तरह की सीमा पर पीछे की ओर चलना चाहते हैं, तो आप हमेशा उपयोग कर सकते हैं downto:

$ r = 10..6
=> 10..6

$ (r.first).downto(r.last).each { |i| puts i }
10
9
8
7
6

यहाँ दूसरों से कुछ और विचार हैं कि क्यों यह कठिन है कि दोनों इसे अनुमति दें और लगातार रिवर्स-रेंज के साथ व्यवहार करें।


10
मुझे लगता है कि 1 से 100 तक या 100 से 1 तक की सीमा पर पुनरावृति का मतलब है चरण 1 का उपयोग करना। यदि कोई अलग कदम चाहता है, तो डिफ़ॉल्ट को बदल देता है। इसी तरह, मेरे लिए (कम से कम) 1 जनवरी से 16 अगस्त तक चलने का मतलब है दिनों के साथ कदम बढ़ाना। मुझे लगता है कि अक्सर ऐसा कुछ होता है, जिस पर हम आम तौर पर सहमत हो सकते हैं, क्योंकि हम सहज रूप से इस तरह से इसका मतलब निकालते हैं। आपके उत्तर के लिए धन्यवाद, आपके द्वारा दी गई लिंक भी उपयोगी थी।
पंद्रह

3
मुझे अभी भी लगता है कि कई श्रेणियों के लिए "सहज" पुनरावृत्तियों को परिभाषित करना लगातार करना चुनौतीपूर्ण है, और मैं इस बात से सहमत नहीं हूं कि इस तरह से तारीखों को पुनरावृत्त करना सहज रूप से 1 दिन के बराबर एक कदम है - आखिरकार, एक दिन पहले से ही एक सीमा होती है समय (आधी रात से आधी रात तक)। उदाहरण के लिए, कौन कहता है कि "1 जनवरी से 18 अगस्त" (बिल्कुल 20 सप्ताह) दिनों के बजाय हफ्तों का पुनरावृत्ति नहीं है? घंटे, मिनट या दूसरे से क्यों नहीं?
जॉन फेमिनाला

8
.eachबेमानी है, 5.downto(1) { |n| puts n }ठीक काम करता है। इसके अलावा, सभी के बजाय r.first r.last सामान, बस करो (6..10).reverse_each
mk12

@ Mk12: 100% सहमत हूं, मैं सिर्फ नए रूबिस्टों की खातिर सुपर-स्पष्ट होने की कोशिश कर रहा था। शायद यह बहुत भ्रामक है, हालांकि।
जॉन फेमिनेला

जब वर्षों को एक = f.select :model_year, (Time.zone.now.year + 1).downto(Time.zone.now.year - 100).to_a
एरिक नॉरक्रॉस

92

कैसे (0..1).reverse_eachजिसके बारे में सीमा पीछे की ओर iterates?


1
यह अस्थायी सरणी बनाता है, कम से कम 2.4.1 में ruby-doc.org/core-2.4.1/Enumerable.html#method-i-reverse_each
Kolen

1
यह मेरे लिए तारीखों की एक श्रेणी को छाँटने का काम करता है (Date.today.beginning_of_year..Date.today.yesterday).reverse_eachधन्यवाद
डेनियल

18

रूबी में एक सीमा से अधिक रेंज में पहली वस्तु पर विधि को eachकॉल करना succ

$ 4.succ
=> 5

और 5 रेंज के बाहर है।

आप इस हैक के साथ रिवर्स पुनरावृत्ति अनुकरण कर सकते हैं:

(-4..0).each { |n| puts n.abs }

जॉन ने बताया कि अगर यह 0. फैला है तो यह काम नहीं करेगा।

>> (-2..2).each { |n| puts -n }
2
1
0
-1
-2
=> -2..2

नहीं कह सकता मैं वास्तव में उनमें से किसी को पसंद करता हूं क्योंकि वे इरादे को अस्पष्ट करते हैं।


2
नहीं। लेकिन उपयोग करने के बजाय -1 से गुणा करके। आप कर सकते हैं।
जोनास एल्फ्रॉस्टेम

12

"प्रोग्रामिंग रूबी" पुस्तक के अनुसार, रेंज ऑब्जेक्ट रेंज के दो अंत बिंदुों को संग्रहीत करता है और .succसदस्य का उपयोग मध्यवर्ती मान उत्पन्न करने के लिए करता है। आप अपनी सीमा में किस प्रकार के डेटा का उपयोग कर रहे हैं, इस पर निर्भर करते हुए, आप हमेशा सदस्य का उप Integer- वर्ग बना सकते हैं और .succसदस्य को फिर से परिभाषित कर सकते हैं ताकि यह उल्टे चलने वाले की तरह काम करे (आप शायद फिर से परिभाषित भी करना चाहेंगे .next)।

तुम भी एक सीमा का उपयोग किए बिना आप के लिए देख रहे हैं परिणाम प्राप्त कर सकते हैं। इसे इस्तेमाल करे:

4.step(0, -1) do |i|
    puts i
end

यह -1 के चरणों में 4 से 0 तक होगा। हालाँकि, मुझे नहीं पता कि यह इंटीगर तर्कों के अलावा किसी और चीज के लिए काम करेगा या नहीं।



5

तुम भी एक forपाश का उपयोग कर सकते हैं :

for n in 4.downto(0) do
  print n
end

जो प्रिंट करता है:

4
3
2
1
0

3

अगर सूची इतनी बड़ी नहीं है। मुझे लगता [*0..4].reverse.each { |i| puts i } है कि सबसे सरल तरीका है।


2
आईएमओ यह आम तौर पर यह मान लेना अच्छा है कि यह बड़ा है। मुझे लगता है कि आम तौर पर इसका पालन करना सही विश्वास और आदत है। और जैसा कि शैतान कभी नहीं सोता है, मुझे खुद पर भरोसा नहीं है कि मुझे याद है कि मैंने एक सरणी पर कहां ध्यान दिया था। लेकिन आप सही हैं, अगर हमारे पास 0 और 4 स्थिर हैं, तो सरणी पर पुनरावृत्ति करने से कोई समस्या नहीं हो सकती है।
पंद्रह

1

जैसा कि bta ने कहा, कारण यह है कि इसकी शुरुआत के लिए Range#eachभेजता succहै, फिर उस succकॉल के परिणाम तक, और इसी तरह जब तक कि परिणाम अंतिम मूल्य से अधिक न हो। आप कॉल करके 4 से 0 नहीं प्राप्त कर सकते हैं succ, और वास्तव में आप पहले से ही अंत से अधिक शुरू करते हैं।


1

मैं एक और संभावना जोड़ता हूं कि रिवर्स रेंज पर पुनरावृत्ति को कैसे महसूस किया जाए। मैं इसका उपयोग नहीं करता, लेकिन यह एक संभावना है। यह बंदर पैच माणिक कोर वस्तुओं के लिए थोड़ा जोखिम भरा है।

class Range

  def each(&block)
    direction = (first<=last ? 1 : -1)
    i = first
    not_reached_the_end = if first<=last
                            lambda {|i| i<=last}
                          else
                            lambda {|i| i>=last}
                          end
    while not_reached_the_end.call(i)
      yield i
      i += direction
    end
  end
end

0

यह मेरे आलसी उपयोग के मामले के लिए काम किया

(-999999..0).lazy.map{|x| -x}.first(3)
#=> [999999, 999998, 999997]

0

ओपी ने लिखा

यह मुझे अजीब लगता है कि ऊपर का निर्माण अपेक्षित परिणाम नहीं देता है। उसका क्या कारण है? जब यह व्यवहार उचित हो तो क्या स्थितियाँ हैं?

नहीं 'यह किया जा सकता है?' लेकिन उस प्रश्न का उत्तर देने के लिए जिसे वास्तव में पूछे जाने वाले प्रश्न से पहले नहीं पूछा गया था:

$ irb
2.1.5 :001 > (0..4)
 => 0..4
2.1.5 :002 > (0..4).each { |i| puts i }
0
1
2
3
4
 => 0..4
2.1.5 :003 > (4..0).each { |i| puts i }
 => 4..0
2.1.5 :007 > (0..4).reverse_each { |i| puts i }
4
3
2
1
0
 => 0..4
2.1.5 :009 > 4.downto(0).each { |i| puts i }
4
3
2
1
0
 => 4

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

वास्तव में पूछे गए सवाल का जवाब देने के लिए ...

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

nil.to_s
   .to_s
   .inspect

परिणाम "" लेकिन

nil.to_s
#  .to_s   # Don't want this one for now
   .inspect

का परिणाम

 syntax error, unexpected '.', expecting end-of-input
 .inspect
 ^

आप शायद उम्मीद करेंगे << और arrays के लिए अपील करने के लिए एक ही धक्का, लेकिन

a = []
a << *[:A, :B]    # is illegal but
a.push *[:A, :B]  # isn't.

आप शायद अपने यूनिक्स कमांड-लाइन समकक्ष की तरह व्यवहार करने के लिए 'grep' की उम्मीद करेंगे, लेकिन यह === मिलान करता है = इसके नाम के बावजूद नहीं।

$ echo foo | grep .
foo
$ ruby -le 'p ["foo"].grep(".")'
[]

विभिन्न तरीके अप्रत्याशित रूप से एक दूसरे के लिए उपनाम हैं, इसलिए आपको एक ही चीज़ के लिए कई नाम सीखना होगा - जैसे findऔर detect- भले ही आप ज्यादातर डेवलपर्स को पसंद करते हैं और केवल एक या दूसरे का उपयोग करते हैं। ज्यादा एक ही के लिए चला जाता है size, countऔर length, वर्ग है जो प्रत्येक को अलग ढंग से परिभाषित करते हैं, या एक या दो सब पर परिभाषित नहीं करते के लिए छोड़कर।

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

पर्यावरण चर वस्तु, ENV 'मर्ज' का समर्थन नहीं करता है, इसलिए आपको लिखना होगा

 ENV.to_h.merge('a': '1')

एक बोनस के रूप में, आप अपने या किसी और के निरंतर को फिर से परिभाषित कर सकते हैं यदि आप अपना दिमाग बदलते हैं कि उन्हें क्या होना चाहिए।


यह किसी भी तरह से, आकार या रूप में प्रश्न का उत्तर नहीं देता है। यह कुछ भी नहीं है, लेकिन लेखक रूबी के बारे में पसंद नहीं करता है।
डब्ल्यू पर Jörg W Mittag

उस प्रश्न का उत्तर देने के लिए अद्यतन किया गया है जो वास्तव में पूछे गए उत्तर के अलावा नहीं पूछा गया है। शेख़ी: क्रिया 1. गुस्से में, शर्मिंदा तरीके से लंबाई में बोलें या चिल्लाएं। मूल उत्तर क्रोधित या भावहीन नहीं था: यह उदाहरणों के साथ एक विचारित प्रतिक्रिया थी।
android.weasel

@ JörgWMittag मूल प्रश्न में यह भी शामिल है: यह मुझे अजीब लगता है कि उपरोक्त निर्माण अपेक्षित परिणाम नहीं देता है। उसका क्या कारण है? ऐसी परिस्थितियाँ क्या हैं जब यह व्यवहार उचित है? इसलिए वह कारणों के बाद है, कोड समाधान नहीं।
Android.weasel

फिर, मैं यह देखने में विफल रहता हूं कि grepकिसी भी तरह से, आकृति या रूप का व्यवहार इस तथ्य से कैसे संबंधित है कि एक खाली सीमा पर पुनरावृत्ति करना कोई विकल्प नहीं है। और न ही मैं देख सकता हूं कि एक खाली सीमा पर चलने वाला यह तथ्य यह है कि कोई भी व्यक्ति किसी भी तरह से आकार या रूप में नहीं है "अंतहीन आश्चर्य" और "बिल्कुल टूट"।
जॉर्ग डब्ल्यू मित्तग

क्योंकि एक सीमा 4..0 का स्पष्ट इरादा [4, 3, 2, 1, 0] है, लेकिन आश्चर्यजनक रूप से एक चेतावनी भी नहीं देता है। इसने ओपी को आश्चर्यचकित कर दिया और इसने मुझे आश्चर्यचकित कर दिया, और कई अन्य लोगों पर संदेह किया। मैंने आश्चर्यजनक व्यवहार के अन्य उदाहरण सूचीबद्ध किए। मैं और अधिक उद्धृत कर सकता हूं, अगर आपको पसंद है। एक बार जब कुछ निश्चित मात्रा में आश्चर्यजनक व्यवहार से अधिक प्रदर्शित होता है, तो यह 'टूट' के क्षेत्र में बहाव शुरू हो जाता है। एक बिट की तरह कैसे स्थिरांक एक चेतावनी जब अधिलेखित, विशेष रूप से जब तरीके नहीं उठाते हैं।
Android.weasel

0

मेरे लिए सबसे सरल तरीका है:

[*0..9].reverse

गणना के लिए पुनरावृति का दूसरा तरीका:

(1..3).reverse_each{|v| p v}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.