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_indexolast.Hashse 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_indexdisculpas. Sí, puedo ver que surgirá; solo tratando de aclarar la pregunta. Personalmente, la mejor respuesta para mí es el uso de,.lastpero 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 endfuente
.lastfuera del bucle.users.each_with_index do |(key, value), index| #your code endSi 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 userfuente
.lastque 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)lastnunca 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 endfuente
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 endfuente
h = { :a => :aa, :b => :bb } h.each_with_index do |(k,v), i| puts ' Put last element logic here' if i == h.size - 1 endfuente
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.lastfuente
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 endfuente
StopIterationestá 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. (StopIterationEs un descendiente deStandardErroryIndexError; 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 ...)nextpara un valor especial de fin de iteración, y no es necesario llamar a algún tipo denext?predicado antes de llamarnext".loop dotiene un implícitorescueal encontrar unStopIteration; se usa específicamente cuando se itera externamente unEnumeratorobjeto.loop do; my_enum.next; enditerarámy_enumy saldrá al final; no es necesario poner unrescue StopIterationahí. (Tienes que hacerlo si usaswhileountil.)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 endfuente
last, el conjunto de claves estará desordenado, por lo que esta respuesta devolverá resultados incorrectos / aleatorios de todos modos.