Tell the end of a .each loop in ruby
67,388
Solution 1
users.each_with_index do |u, index|
# some code
if index == users.size - 1
# code for the last user
end
end
Solution 2
If it's an either/or situation, where you're applying some code to all but the last user and then some unique code to only the last user, one of the other solutions might be more appropriate.
However, you seem to be running the same code for all users, and some additional code for the last user. If that's the case, this seems more correct, and more clearly states your intent:
users.each do |u|
#code for everyone
end
users.last.do_stuff() # code for last user
Solution 3
I think a best approach is:
users.each do |u|
#code for everyone
if u.equal?(users.last)
#code for the last user
end
end
Solution 4
Did you tried each_with_index
?
users.each_with_index do |u, i|
if users.size-1 == i
#code for last items
end
end
Solution 5
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
Related videos on Youtube
Author by
Splashlin
Updated on April 14, 2022Comments
-
Splashlin about 2 years
If i have a loop such as
users.each do |u| #some code end
Where users is a hash of multiple users. What's the easiest conditional logic to see if you are on the last user in the users hash and only want to execute specific code for that last user so something like
users.each do |u| #code for everyone #conditional code for last user #code for the last user end end
-
Shadwell over 13 yearsDo you really mean a hash? Ordering on a hash is not always reliable (depending on how you add things to the hash and what ruby version you are using). With unreliable ordering the 'last' item will not be consistent. The code in the question and the answers you are getting are more appropriate to an array or enumerable. For example, hashes don't have
each_with_index
orlast
methods. -
Raphomet over 13 years
Hash
mixes in Enumerable, so it does haveeach_with_index
. Even if the hash keys aren't sorted, this sort of logic comes up all the time when rendering views, where the last item might be displayed differently regardless of whether it's actually "last" in any data-meaningful sense. -
Shadwell over 13 yearsOf course, quite right, hashes do have
each_with_index
, apologies. Yep, I can see that it would come up; just trying to clarify the question. Personally the best answer for me is the use of.last
but that doesn't apply for a hash only an array. -
oligan over 13 yearsDuplicate of Magic First and Last Indicator in a Loop in Ruby/Rails?, apart from this being a hash rather than an array.
-
Sam Saffron over 13 years@Andrew agree its totally related, however meagars awesome little answer shows how it is not exactly a dupe.
-
oligan over 13 years@Sam: Could Meagar's answer be appropriate for the other question as well?
-
Sam Saffron over 13 years@Andrew , I'm not sure I don't think so, the other question has no common clause for all the items in the collection
-
-
Jeremy over 13 years+1 for not needing a conditional, if that's appropriate. (of course, I did here)
-
evanrmurphy over 11 yearsThe problem with this answer is that if the last user also occurs earlier in the list, then the conditional code will get called multiple times.
-
Artemix almost 11 yearsIs it an answer that improves someone else's answer? Please post which answer mentions 'last' method and what do you propose to overcome this issue.
-
bcackerman over 10 yearsProblem with this is a conditional is ran through each time. use
.last
outside the loop. -
user229044 over 10 yearsThis is not a good solution to this problem. Exceptions shouldn't be abused for simple flow control, they're for exceptional situations.
-
user229044 over 10 yearsFor the versions of Ruby which don't have a
last
, the set of keys will be unordered, so this answer will return wrong/random results anyways. -
HUB over 9 yearsI'd just add that if you're iterating over a hash, you have to write it like:
users.each_with_index do |(key, value), index| #your code end
-
ant over 8 years@meagar won't this loop trough users twice?
-
user229044 over 8 years@ant No, there is one loop and one call to
.last
which has nothing to do with looping. -
ant over 8 years@meagar so in order to get to the last it doesn't internally loop until the last element? it has a way of accessing the element directly without looping?
-
user229044 over 8 years@ant No, there is no internal looping involved in
.last
. The collection is already instantiated, it's just a simple accessing of an array. Even if the collection had not already been loaded (as in, it was still an unhydrated ActiveRecord relation)last
still never loops to get the last value, that would be wildly inefficient. It simply modifies the SQL query to return the last record. That said, this collection has already been loaded by the.each
, so there is no more complexity involved than if you didx = [1,2,3]; x.last
. -
ant over 8 years@meagar gotcha, thanks for the explanation, well said!
-
WhiteTiger over 8 yearsI know it's not entirely the same question, but this code works better I think if you want to do something to everyone BUT the last user, so I'm upvoting since that was what I was looking for
-
Nafaa Boutefer over 8 yearsyou have to use
u.equal?(users.last)
, theequal?
method compares the object_id, not the value of the object. But this will not work with symboles and numbers. -
coderuby almost 8 years@BeniBela No, [-1] is the last element. There is no [-0]. So the second to last is [-2].
-
Kevin Walsh over 7 years
users[0..-2]
is correct, as isusers[0...-1]
. Note the different range operators..
vs...
, see stackoverflow.com/a/9690992/67834 -
Adamantish over 7 years@ant I'm late to the party here but something that might be too obvious to @meagar to mention but wasn't always to me: Unlike an AR relation which will need to run an (efficient) database search to find the last item, a ruby array or hash already knows its own length. It has it pre-stored as an internal instance variable. This means it already knows exactly where to find the last item. In general Methods like
count
,last
orfind
may do the same thing for different data structures / AR objects but work very differently underneath. -
Adamantish over 7 years@meagar This is actually nearly quite cool. I agree that unrescued exceptions or ones that need to be passed up to a higher method should only be for exceptional situations. This, however, is a neat (and apparently only) way of getting access to ruby's native knowledge of where an iterator ends. If there is another way that, is of course, preferred. The only real issue I'd take with this is that it appears to skip and do nothing for the first item. Fixing that would take it over the boundary of clunkiness.
-
BobRodes over 4 years@meagar Sorry for an "argument from authority," but Matz disagrees with you. In fact,
StopIteration
is designed for the precise reason of handling loop exits. From Matz's book: "This may seem unusual—an exception is raised for an expected termination condition rather than an unexpected and exceptional event. (StopIteration
is a descendant ofStandardError
andIndexError
; note that it is one of the only exception classes that does not have the word “error” in its name.) Ruby follows Python in this external iteration technique. (more...) -
BobRodes over 4 years(...) By treating loop termination as an exception, it makes your looping logic extremely simple; there is no need to check the return value of
next
for a special end-of-iteration value, and there is no need to call some kind ofnext?
predicate before callingnext
." -
BobRodes over 4 years@Adamantish It should be noted that
loop do
has an implicitrescue
when encountering aStopIteration
; it's specifically used when externally iterating anEnumerator
object.loop do; my_enum.next; end
will iteratemy_enum
and exit at the end; no need to put arescue StopIteration
in there. (You do have to if you usewhile
oruntil
.) -
user229044 over 4 years@BobRodes That's extremely interesting. Which book is that?
-
BobRodes over 4 years@meagar I thought so too when I read it. It's one interesting book, and both readable and informative. Here's the Amazon link.