क्या रूबी में एक "डू ... जबकि" लूप है?


453

उपयोगकर्ता को नामों में दर्ज करने देने के लिए मैं इस कोड का उपयोग कर रहा हूं, जबकि प्रोग्राम उन्हें एक सरणी में संग्रहीत करता है जब तक कि वे एक खाली स्ट्रिंग दर्ज नहीं करते हैं (उन्हें प्रत्येक नाम के बाद दर्ज करना होगा):

people = []
info = 'a' # must fill variable with something, otherwise loop won't execute

while not info.empty?
    info = gets.chomp
    people += [Person.new(info)] if not info.empty?
end

यह कोड लूप में बहुत अच्छा लगेगा ... जबकि लूप:

people = []

do
    info = gets.chomp
    people += [Person.new(info)] if not info.empty?
while not info.empty?

इस कोड में मुझे कुछ यादृच्छिक स्ट्रिंग के लिए जानकारी असाइन करने की आवश्यकता नहीं है।

दुर्भाग्य से इस प्रकार का लूप रूबी में मौजूद नहीं है। क्या कोई ऐसा करने का बेहतर तरीका सुझा सकता है?


1
मुझे लगता है कि लूप अच्छे लग रहे हैं, और पढ़ने में आसान है।
मैग्ने

1
@Jeremy Ruten, वहाँ कोई मौका आप Siwei शेन के जवाब देने के लिए स्वीकार किए जाते हैं जवाब बदलने में रुचि होगी है loop do; ...; break if ...; end?
डेविड विनीकी

जवाबों:


645

चेतावनी :

begin <code> end while <condition>रूबी के लेखक Matz द्वारा अस्वीकार कर दिया गया है। इसके बजाय वह सुझाव देता है Kernel#loop, उदाहरण के लिए

loop do 
  # some code here
  break if <condition>
end 

यहाँ 23 नवंबर 2005 को एक ईमेल एक्सचेंज है जहाँ मात्ज़ बताता है:

|> Don't use it please.  I'm regretting this feature, and I'd like to
|> remove it in the future if it's possible.
|
|I'm surprised.  What do you regret about it?

Because it's hard for users to tell

  begin <code> end while <cond>

works differently from

  <code> while <cond>

RosettaCode विकी की एक समान कहानी है:

नवंबर 2005 के दौरान, रूबी के निर्माता, युकीहिरो मात्सुमोतो ने इस लूप फीचर पर खेद जताया और कर्नेल # लूप का उपयोग करने का सुझाव दिया।


18
सटीक। यह begin end whileतरीका सही नहीं लगा। मुझे टीम के बाकी खिलाड़ियों को समझाने के लिए मुझे चारा देने के लिए धन्यवाद।
जोशुआ पिंटर

2
ऐसा लगता है कि शुरू-अंत-जबकि लूप वास्तव में लूप चलाने से पहले की स्थिति का मूल्यांकन कर रहा है। लूप के दौरान और नियमित रूप से अंतर यह है कि यह कम से कम एक बार चलाने की गारंटी है। यह सिर्फ करने के लिए पर्याप्त है ... जबकि समस्याओं का कारण है।
user1992284

4
इसलिए, जहां तक ​​मैंने अच्छी तरह से समझा है, शुरू-अंत-जबकि "पछतावा" होता है क्योंकि संशोधक के शब्दार्थ का उल्लंघन होता है, अर्थात: ब्लॉक को निष्पादित करने से पहले उनकी जांच की जाती है, उदाहरण के लिए: k k डालता है! K.nil ?. यहाँ 'if' एक 'संशोधक' है: यह 'BE kORE' को निर्धारित करने के क्रम में पहले से जाँच की जाती है कि 'k का कथन' निष्पादित कर रहा है। क्या तब तक नहीं है जब तक / जब तक कि लूप न हो (जब एक शुरुआत-अंत ब्लॉक के संशोधक के रूप में उपयोग किया जाता है) !), पहले निष्पादन के बाद मूल्यांकन किया जाता है। फिर भी यह पछतावा का कारण है, लेकिन क्या हमारे पास एक पुराने फोरम पोस्ट की तुलना में कुछ 'अधिक मजबूत' है, एक आधिकारिक पदावनति की तरह जैसे कि यह कई अन्य अवसरों में होने के लिए उपयोग करता है?
अगस्टिनोक्स

2
मुझे यह पता लगाने में शर्मनाक समय लगा कि मेरे इस रूबी 'डू-जबकि' लूप का उपयोग क्यों नहीं किया गया। आपको सी-स्टाइल को अधिक बारीकी से नकल करने के लिए 'जब तक' का उपयोग करना चाहिए, अन्यथा आप मेरी तरह समाप्त हो सकते हैं और स्थिति को उल्टा करना भूल सकते हैं: पी
कॉनर क्लार्क

1
@James लिंक्ड मेल के अनुसार, उन्होंने कहा कि वह इसे जोड़कर "पछतावा" कर रहे थे। कभी-कभी लोग गलती करते हैं, भले ही वे भाषा डिजाइनर हों।
Xiong Chiamiov

188

Tempfile#initializeरूबी कोर लाइब्रेरी में स्रोत को पढ़ते हुए मुझे निम्नलिखित स्निपेट मिले :

begin
  tmpname = File.join(tmpdir, make_tmpname(basename, n))
  lock = tmpname + '.lock'
  n += 1
end while @@cleanlist.include?(tmpname) or
  File.exist?(lock) or File.exist?(tmpname)

पहली नज़र में, मुझे लगा कि मॉडिफाई का मूल्यांकन शुरू होने से पहले ... अंत तक हो जाएगा, लेकिन ऐसा नहीं है। का निरीक्षण करें:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil

जैसा कि आप उम्मीद करेंगे, लूप निष्पादित करना जारी रखेगा जबकि संशोधक सही है।

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil

जबकि मुझे यह मुहावरा फिर कभी न देखने में खुशी होगी, शुरू करें ... अंत काफी शक्तिशाली है। निम्नलिखित एक आम मुहावरा है जिसमें बिना पैरा के एक लाइनर विधि को याद किया जाता है:

def expensive
  @expensive ||= 2 + 2
end

यहाँ एक बदसूरत, लेकिन कुछ और जटिल याद करने का त्वरित तरीका है:

def expensive
  @expensive ||=
    begin
      n = 99
      buf = "" 
      begin
        buf << "#{n} bottles of beer on the wall\n" 
        # ...
        n -= 1
      end while n > 0
      buf << "no more bottles of beer" 
    end
end

मूल रूप से जेरेमी वूरिस द्वारा लिखित । सामग्री को यहां कॉपी किया गया है क्योंकि ऐसा लगता है कि इसे उद्गम स्थल से नीचे ले जाया गया है। कॉपियां वेब आर्काइव और रूबी बज़ फ़ोरम में भी पाई जा सकती हैं । छिपकली को मारना



56
यही कारण है कि जब किसी बाहरी साइट से लिंक होता है, तो मैं हमेशा प्रासंगिक जानकारी को अपने उत्तर में कॉपी करना सुनिश्चित करता हूं।
davr

10
आप शुरुआत की सामग्री से पहले मूल्यांकन करते समय संशोधित होने की उम्मीद क्यों करेंगे ... अंत? यह तरीका है..इसलिए लूप्स काम करने वाले हैं। और आप "इस मुहावरे को फिर कभी न देखने के लिए खुश क्यों होंगे?" इसके साथ गलत क्या है? मैं उलझन में हूं।
bergie3000

2
शुरू ... अंत एक ब्लॉक की तरह दिखता है, इसी तरह {...}। इसमें कुछ भी गलत नहीं है।
विक्टर पुडेयव

1
-1: सीवेई शेन का जवाब बताता है कि begin .. endकुछ हद तक डूब गया है। loop do .. break if <condition>इसके बजाय उपयोग करें ।
केविन

102

ऐशे ही:

people = []

begin
  info = gets.chomp
  people += [Person.new(info)] if not info.empty?
end while not info.empty?

संदर्भ: रूबी के छिपे हुए {} जबकि () लूप


1
हे, यह करने के लिए पीटा। अरे नहीं।
Blorgbeard

यदि कोई इनपुट नहीं है, तो क्या यह कोड सरणी में खाली स्ट्रिंग जोड़ देगा?
एंड्रयू सिप

1
यद्यपि यह यहां लागू नहीं होता है, लेकिन शुरुआती-अंत-निर्माण की एक समस्या यह है कि अन्य सभी रूबी निर्माणों के विपरीत, यह अंतिम अभिव्यक्ति का मूल्य नहीं लौटाता है: "1 अंत शुरू होता है जबकि झूठी" रिटर्न एनआईएल (1 नहीं, 1) असत्य नहीं)
tokland

9
आप इसके until info.empty?बजाय उपयोग कर सकते हैं while not info.empty?
एंड्रयू ग्रिम

वास्तव में @AndrewR इस तरह की बात है .. तुलना करने से पहले चीजों को करने के लिए .. डिप्लोमा ("शेष = # {गिनती}) करते हुए (गणना> 0) ... मुझे" शेष = 0 "का प्रदर्शन मिलता है। एकदम सही!
baash05

45

इस बारे में कैसा है?

people = []

until (info = gets.chomp).empty?
  people += [Person.new(info)]
end

4
अच्छा है, और अधिक सुंदर।
Blorgbeard

23
लेकिन यह "नहीं है ... जबकि" लूप है। :)
अलेक्जेंडर प्रोकोफ़ेव

4
लेकिन यह इस मामले में एक ही बात करता है, जब तक कि मैं गलत नहीं हूँ
Blorgbeard बाहर है

18
@Blorgbeard, एक do..ward लूप हमेशा एक बार चलता है, फिर यह देखने के लिए मूल्यांकन करता है कि क्या इसे जारी रखना चाहिए। एक पारंपरिक समय / जब तक लूप 0 बार चल सकता है। यह एक बड़ा अंतर नहीं है, लेकिन वे अलग हैं।
स्कॉट स्वेज़ेई

5
@ सच, ​​यह सच है - मेरा मतलब सिर्फ यह है कि यह कोड ओपी के बराबर है, भले ही यह एक do / का उपयोग नहीं करता है। यद्यपि वास्तव में, यह कोड हालत में लूप के "काम" का आधा हिस्सा करता है, इसलिए यह लूप या तो पारंपरिक नहीं है - यदि स्थिति मेल नहीं खाती है, तो भी कुछ काम किया जाता है।
Blorgbeard

11

यहां हबर्ड्र के मृत लिंक से पूर्ण पाठ लेख मेरे ब्लॉग पर दिया गया है।

Tempfile#initializeरूबी कोर लाइब्रेरी में स्रोत को पढ़ते हुए मुझे निम्नलिखित स्निपेट मिले :

begin
  tmpname = File.join(tmpdir, make_tmpname(basename, n))
  lock = tmpname + '.lock'
  n += 1
end while @@cleanlist.include?(tmpname) or
  File.exist?(lock) or File.exist?(tmpname)

पहली नज़र में, मुझे लगा कि whileसंशोधक की सामग्री से पहले मूल्यांकन किया जाएगा begin...end, लेकिन ऐसा नहीं है। का निरीक्षण करें:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil

जैसा कि आप उम्मीद करेंगे, लूप निष्पादित करना जारी रखेगा जबकि संशोधक सही है।

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil

जबकि मैं इस मुहावरे को फिर कभी नहीं देख पाऊंगा, begin...endकाफी शक्तिशाली है। निम्नलिखित एक आम मुहावरा है जिसमें बिना पैरा के एक लाइनर विधि को याद किया जाता है:

def expensive
  @expensive ||= 2 + 2
end

यहाँ एक बदसूरत, लेकिन कुछ और जटिल याद करने का त्वरित तरीका है:

def expensive
  @expensive ||=
    begin
      n = 99
      buf = "" 
      begin
        buf << "#{n} bottles of beer on the wall\n" 
        # ...
        n -= 1
      end while n > 0
      buf << "no more bottles of beer" 
    end
end

10

यह अब सही ढंग से काम करता है:

begin
    # statment
end until <condition>

लेकिन, भविष्य में इसे हटाया जा सकता है, क्योंकि beginबयान प्रतिपक्ष है। देखें: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745

मात्ज़ (रूबी के निर्माता) ने इसे इस तरह से करने की सिफारिश की:

loop do
    # ...
    break if <condition>
end

6

मैं जो इकट्ठा करता हूं, उसमें से मैत्ज़ को निर्माण पसंद नहीं है

begin
    <multiple_lines_of_code>
end while <cond>

क्योंकि, यह शब्दार्थ से अलग है

<single_line_of_code> while <cond>

उस स्थिति में, पहला निर्माण स्थिति की जाँच करने से पहले पहले कोड को निष्पादित करता है, और दूसरा निर्माण कोड को निष्पादित करने से पहले स्थिति का परीक्षण करता है (यदि कभी भी)। मैं इसे दूसरा निर्माण रखने के लिए मैत्ज़ पसंद करता हूं क्योंकि यह बयानों की एक पंक्ति के निर्माण से मेल खाता है।

अगर बयानों के लिए भी मुझे दूसरा निर्माण पसंद नहीं आया। अन्य सभी मामलों में, कंप्यूटर बाएं-से-दाएं (जैसे। || और &&) शीर्ष-से-नीचे कोड निष्पादित करता है। मनुष्यों ने कोड को बाएं से दाएं ऊपर-नीचे पढ़ा।

मैं इसके बजाय निम्नलिखित निर्माणों का सुझाव देता हूं:

if <cond> then <one_line_code>      # matches case-when-then statement

while <cond> then <one_line_code>

<one_line_code> while <cond>

begin <multiple_line_code> end while <cond> # or something similar but left-to-right

मुझे नहीं पता कि क्या वे सुझाव बाकी भाषा के साथ मिलेंगे। लेकिन किसी भी मामले में मैं बाएं से दाएं निष्पादन के साथ-साथ भाषा की स्थिरता को ध्यान में रखता हूं।


3
a = 1
while true
  puts a
  a += 1
  break if a > 10
end

3
यह एक गोटो की तरह लग रहा है। कोड आपके इरादे को पूरा करता है।
गेरहार्ड

मेरे लिए बहुत अच्छा लग रहा है, सिवाय इसके while trueसाथ बदला जा सकता है loop do
डेविड विनीकी

@DavidWiniecki, वास्तव में, के while trueसाथ प्रतिस्थापित किया जा सकता है loop do। लेकिन मैंने लूप के अंदर बहुत सारे पुनरावृत्तियों के साथ दोनों निर्माणों का परीक्षण किया, और पाया कि while trueकम से कम 2x से अधिक तेज है loop do। अंतर स्पष्ट नहीं कर सकते, लेकिन यह निश्चित रूप से वहाँ है। (कोड 2017, दिन 15. के आगमन की जांच करते समय पता चला)
जोकेम शुल्लेनक्लोपर १५'१ Ad

2

यहाँ एक और है:

people = []
1.times do
  info = gets.chomp
  unless info.empty? 
    people += [Person.new(info)]
    redo
  end
end

मैं इसे पसंद करता हूं, क्योंकि unlessयह सही है और मैं unlessअंत में एक 'झूलने' को खोजने के लिए केवल कोड के एक समूह के माध्यम से नहीं पढ़ता (जो कि यहां दिखाया जा सकता है) । यह कोड में एक सामान्य सिद्धांत है कि संशोधक और शर्तों का उपयोग करना आसान होता है जब वे इस तरह 'अप फ्रंट' होते हैं।
माइकल ड्यूरेंट

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

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