रूबी में .each लूप का अंत बताएं


90

अगर मेरे पास एक लूप है जैसे

users.each do |u|
  #some code
end

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

users.each do |u|
  #code for everyone
  #conditional code for last user
    #code for the last user
  end
end

क्या आपके पास वास्तव में एक हैश है? एक हैश पर ऑर्डर करना हमेशा विश्वसनीय नहीं होता (यह इस पर निर्भर करता है कि आप कैसे हैश में चीजें जोड़ते हैं और आप किस माणिक संस्करण का उपयोग कर रहे हैं)। अविश्वसनीय ऑर्डर के साथ 'अंतिम' आइटम संगत नहीं होगा। प्रश्न और आपके द्वारा दिए जा रहे उत्तरों में कोड किसी सरणी या गणना योग्य के लिए अधिक उपयुक्त हैं। उदाहरण के लिए, हैश में each_with_indexया lastविधियाँ नहीं हैं ।
शादवेल

1
HashEnumerable में घोला जा सकता है, तो यह है each_with_index। भले ही हैश कीज़ को छाँटा न गया हो, इस तरह का तर्क विचारों को प्रस्तुत करते समय हर समय सामने आता है, जहाँ किसी भी डेटा-अर्थपूर्ण अर्थ में "अंतिम" होने की परवाह किए बिना अंतिम आइटम को अलग तरीके से प्रदर्शित किया जा सकता है।
रापोमेट

बेशक, काफी सही, hashes है each_with_index, माफी। हां, मैं देख सकता हूं कि यह ऊपर आएगा; बस सवाल स्पष्ट करने की कोशिश कर रहा है। व्यक्तिगत रूप से मेरे लिए सबसे अच्छा जवाब है, .lastलेकिन इसका उपयोग केवल एक सरणी के लिए हैश के लिए लागू नहीं होता है।
शादवेल

रूबी / रेल में लूप में मैजिक फर्स्ट एंड लास्ट इंडिकेटर का डुप्लीकेट ? , इसके अलावा एक सरणी के बजाय एक हैश होने के नाते।
एंड्रयू ग्रिम

1
@Andrew इसके पूरी तरह से संबंधित से सहमत हैं, हालांकि meagars भयानक छोटे से उत्तर से पता चलता है कि यह वास्तव में एक डुबकी नहीं है।
सैम सैफ्रॉन

जवाबों:


146
users.each_with_index do |u, index|
  # some code
  if index == users.size - 1
    # code for the last user
  end
end

4
इसके साथ समस्या एक सशर्त है जिसे हर बार के माध्यम से चलाया जाता है। .lastलूप के बाहर का उपयोग करें ।
bcackerman

3
मैं सिर्फ इतना जोड़ूंगा कि अगर आप हैश से अधिक परेशान कर रहे हैं, तो आपको इसे लिखना होगा:users.each_with_index do |(key, value), index| #your code end
HUB

मुझे पता है कि यह पूरी तरह से एक ही सवाल नहीं है, लेकिन यह कोड बेहतर तरीके से काम करता है, मुझे लगता है कि यदि आप अंतिम उपयोगकर्ता के लिए कुछ करना चाहते हैं, तो इसलिए मैं
अपवोट कर

38

यदि यह या तो / या स्थिति है, जहाँ आप सभी के लिए कुछ कोड लागू कर रहे हैं , लेकिन करने के लिए पिछले उपयोगकर्ता और फिर कुछ अद्वितीय कोड केवल अंतिम उपयोगकर्ता अन्य समाधानों में से एक अधिक उपयुक्त हो सकता है।

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

users.each do |u|
  #code for everyone
end

users.last.do_stuff() # code for last user

2
एक सशर्त की जरूरत नहीं है, अगर यह उचित है। (बेशक, मैंने यहां किया था)
जेरेमी

@meagar इस लूप को दो बार उपयोगकर्ताओं को नहीं देगा?
चींटी

@ नहीं, एक लूप है और एक कॉल है .lastजिसका लूपिंग से कोई लेना-देना नहीं है।
meagar

@ अंतिम तक पहुंचने के लिए अंतिम तत्व तक आंतरिक रूप से लूप नहीं करता है? यह सीधे पाशन के बिना तत्व तक पहुंचने का एक तरीका है?
ant

1
@ नहीं, इसमें कोई आंतरिक लूपिंग शामिल नहीं है .last। संग्रह पहले से ही त्वरित है, यह एक सरणी का सिर्फ एक सरल एक्सेस है। यहां तक ​​कि अगर संग्रह पहले से लोड नहीं किया गया था (जैसा कि, यह अभी भी एक अनियंत्रित ActiveRecord संबंध था) lastअभी भी अंतिम मूल्य प्राप्त करने के लिए कभी भी लूप नहीं करता है , जो बेतहाशा अक्षम होगा। यह पिछले रिकॉर्ड को वापस करने के लिए बस SQL ​​क्वेरी को संशोधित करता है। उस ने कहा, इस संग्रह को पहले से ही लोड किया गया है .each, इसलिए अगर आपने किया तो इससे अधिक जटिलता शामिल नहीं है x = [1,2,3]; x.last
meagar

20

मुझे लगता है कि सबसे अच्छा तरीका है:

users.each do |u|
  #code for everyone
  if u.equal?(users.last)
    #code for the last user
  end
end

22
इस उत्तर के साथ समस्या यह है कि यदि अंतिम उपयोगकर्ता सूची में पहले भी होता है, तो सशर्त कोड को कई बार कहा जाएगा।
evanrmurphy

1
आपको उपयोग करना है u.equal?(users.last), equal?विधि object_id की तुलना करती है, वस्तु का मान नहीं। लेकिन यह सिम्बोल और संख्या के साथ काम नहीं करेगा।
नेफा बाउटफर


6
h = { :a => :aa, :b => :bb }
h.each_with_index do |(k,v), i|
  puts ' Put last element logic here' if i == h.size - 1
end

3

कभी-कभी मुझे तर्क को दो भागों में अलग करना बेहतर लगता है, सभी उपयोगकर्ताओं के लिए एक और पिछले एक के लिए। तो मैं कुछ ऐसा करूंगा:

users[0...-1].each do |user|
  method_for_all_users user
end

method_for_all_users users.last
method_for_last_user users.last

3

आप @ meager के दृष्टिकोण का उपयोग या तो / या स्थिति के लिए भी कर सकते हैं, जहाँ आप कुछ कोड को केवल अंतिम उपयोगकर्ता के लिए और फिर कुछ अद्वितीय कोड पर लागू कर रहे हैं।

users[0..-2].each do |u|
  #code for everyone except the last one, if the array size is 1 it gets never executed
end

users.last.do_stuff() # code for last user

इस तरह से आपको एक सशर्त की आवश्यकता नहीं है!


@ बेनीबेला नं, [-1] अंतिम तत्व है। कोई [-0] नहीं है। तो दूसरा से अंतिम [-2] है।
कोडरुबी

users[0..-2]सही है, जैसा है users[0...-1]। नोट अलग श्रेणी ऑपरेटरों ..बनाम ..., देख stackoverflow.com/a/9690992/67834
एलियट साइक्स

2

एक अन्य उपाय StopIteration से बचाव है:

user_list = users.each

begin
  while true do
    user = user_list.next
    user.do_something
  end
rescue StopIteration
  user.do_something
end

4
यह इस समस्या का एक अच्छा समाधान नहीं है। अपवादों को सरल प्रवाह नियंत्रण के लिए दुरुपयोग नहीं किया जाना चाहिए, वे असाधारण स्थितियों के लिए हैं।
meagar

@meagar यह वास्तव में लगभग काफी अच्छा है। मैं इस बात से सहमत हूं कि अनियंत्रित अपवाद या जिन्हें उच्च पद्धति तक पारित करने की आवश्यकता है, केवल असाधारण स्थितियों के लिए होनी चाहिए। हालांकि, यह रूबी के मूल ज्ञान तक पहुंच प्राप्त करने का एक साफ-सुथरा (और स्पष्ट रूप से केवल) तरीका है जहां एक पुनरावृत्ति समाप्त होती है। अगर वहाँ एक और तरीका है कि, निश्चित रूप से, पसंदीदा है। एकमात्र वास्तविक मुद्दा जो मैं इसके साथ ले जाऊंगा वह यह है कि यह पहले आइटम के लिए कुछ भी नहीं छोड़ता और कुछ भी नहीं करता है। फिक्सिंग जो इसे अव्यवस्था की सीमा पर ले जाएगा।
Adamantish

2
@meagar "अधिकार से तर्क" के लिए क्षमा करें, लेकिन मैट्स आपसे असहमत हैं। वास्तव में, StopIterationलूप निकास से निपटने के सटीक कारण के लिए डिज़ाइन किया गया है। Matz की पुस्तक से: "यह लग सकता है असामान्य-एक अपवाद नहीं बल्कि एक अप्रत्याशित और असाधारण घटना से एक उम्मीद समाप्ति हालत के लिए उठाया है (। StopIterationका वंशज है StandardErrorऔर IndexError; टिप्पणी है कि यह केवल अपवाद वर्गों है कि शब्द नहीं है में से एक है इसके नाम में "त्रुटि"।) रूबी इस बाहरी पुनरावृत्ति तकनीक में पायथन का अनुसरण करती है। (अधिक ...)
बॉबरोड्स

(...) एक अपवाद के रूप में लूप समाप्ति का इलाज करके, यह आपके लूपिंग तर्क को बहुत सरल बनाता है; nextविशेष एंड-ऑफ़- next?next
इटरेशन

1
@ अदमनिष्ठ यह ध्यान दिया जाना चाहिए कि मुठभेड़ करते समय loop doएक निहित rescueहै StopIteration; यह विशेष रूप से तब उपयोग किया जाता है जब बाहरी रूप से किसी Enumeratorवस्तु को पुनरावृत्त करता है। अंत में loop do; my_enum.next; endपुनरावृति my_enumऔर निकास होगा ; rescue StopIterationवहाँ एक में डाल करने की आवश्यकता नहीं है । (आप का उपयोग करने के लिए है whileया नहीं है until।)
BobRodes

0

माणिक के कुछ संस्करणों के लिए हैश के लिए कोई अंतिम विधि नहीं है

h = { :a => :aa, :b => :bb }
last_key = h.keys.last
h.each do |k,v|
    puts "Put last key #{k} and last value #{v}" if last_key == k
end

क्या यह ऐसा उत्तर है जो किसी और के उत्तर को बेहतर बनाता है? कृपया पोस्ट करें जो 'अंतिम' पद्धति का उल्लेख करता है और इस मुद्दे को दूर करने के लिए आप क्या प्रस्ताव देते हैं।
आर्टेमिक्स

रूबी के संस्करणों के लिए, जिनके पास ए नहीं है last, चाबियों का सेट अनियंत्रित हो जाएगा, इसलिए यह उत्तर गलत / यादृच्छिक परिणाम देगा।
meagar
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.