Si tengo un bucle como
users.each do |u|
#some code
end
Donde usuarios es un hash de varios usuarios. ¿Cuál es la lógica condicional más fácil para ver si está en el último usuario en el hash de usuarios y solo desea ejecutar un código específico para ese último usuario?
users.each do |u|
#code for everyone
#conditional code for last user
#code for the last user
end
end
ruby-on-rails
ruby
loops
each
Splashlin
fuente
fuente
each_with_index
olast
.Hash
se mezcla en Enumerable, por lo que tieneeach_with_index
. Incluso si las claves hash no están ordenadas, este tipo de lógica surge todo el tiempo al representar vistas, donde el último elemento puede mostrarse de manera diferente independientemente de si es realmente "último" en algún sentido significativo para los datos.each_with_index
disculpas. Sí, puedo ver que surgirá; solo tratando de aclarar la pregunta. Personalmente, la mejor respuesta para mí es el uso de,.last
pero eso no se aplica a un hash solo a una matriz.Respuestas:
users.each_with_index do |u, index| # some code if index == users.size - 1 # code for the last user end end
fuente
.last
fuera del bucle.users.each_with_index do |(key, value), index| #your code end
Si se trata de una situación de una u otra, en la que está aplicando un código a todos menos al último usuario y luego un código único solo al último usuario, una de las otras soluciones podría ser más apropiada.
Sin embargo, parece que está ejecutando el mismo código para todos los usuarios y algún código adicional para el último usuario. Si ese es el caso, esto parece más correcto y establece más claramente su intención:
users.each do |u| #code for everyone end users.last.do_stuff() # code for last user
fuente
.last
que no tiene nada que ver con el bucle..last
. La colección ya está instanciada, es solo un simple acceso a una matriz. Incluso si la colección aún no se había cargado (como en, todavía era una relación ActiveRecord no hidratada)last
nunca se repite para obtener el último valor, eso sería tremendamente ineficiente. Simplemente modifica la consulta SQL para devolver el último registro. Dicho esto, esta colección ya ha sido cargada por el.each
, por lo que no hay más complejidad involucrada que si lo hicierax = [1,2,3]; x.last
.Creo que el mejor enfoque es:
users.each do |u| #code for everyone if u.equal?(users.last) #code for the last user end end
fuente
u.equal?(users.last)
, elequal?
método compara el object_id, no el valor del objeto. Pero esto no funcionará con símbolos y números.¿Lo intentaste
each_with_index
?users.each_with_index do |u, i| if users.size-1 == i #code for last items end end
fuente
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
fuente
A veces me parece mejor separar la lógica en dos partes, una para todos los usuarios y otra para la última. Entonces haría algo como esto:
users[0...-1].each do |user| method_for_all_users user end method_for_all_users users.last method_for_last_user users.last
fuente
Puede usar el enfoque de @ meager también para una situación de una u otra, en la que está aplicando un código a todos menos al último usuario y luego un código único solo al último usuario.
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
¡De esta manera no necesitas un condicional!
fuente
users[0..-2]
es correcto, como estáusers[0...-1]
. Tenga en cuenta los diferentes operadores de rango..
vs...
, consulte stackoverflow.com/a/9690992/67834Otra solución es rescatar de StopIteration:
user_list = users.each begin while true do user = user_list.next user.do_something end rescue StopIteration user.do_something end
fuente
StopIteration
está diseñado por la razón precisa de manejar salidas de bucle. Del libro de Matz: "Esto puede parecer inusual: se genera una excepción para una condición de terminación esperada en lugar de un evento inesperado y excepcional. (StopIteration
Es un descendiente deStandardError
yIndexError
; tenga en cuenta que es una de las únicas clases de excepción que no tiene la palabra "Error" en su nombre.) Ruby sigue a Python en esta técnica de iteración externa. (Más ...)next
para un valor especial de fin de iteración, y no es necesario llamar a algún tipo denext?
predicado antes de llamarnext
".loop do
tiene un implícitorescue
al encontrar unStopIteration
; se usa específicamente cuando se itera externamente unEnumerator
objeto.loop do; my_enum.next; end
iterarámy_enum
y saldrá al final; no es necesario poner unrescue StopIteration
ahí. (Tienes que hacerlo si usaswhile
ountil
.)No existe un último método de hash para algunas versiones de ruby
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
fuente
last
, el conjunto de claves estará desordenado, por lo que esta respuesta devolverá resultados incorrectos / aleatorios de todos modos.