2010-10-22 22 views
72

Si tengo un bucle comoDile al final de un bucle .Cada en rubí

users.each do |u| 
    #some code 
end 

Cuando los usuarios es un hash de varios usuarios. ¿Cuál es la lógica condicional más fácil de ver si está en el último usuario en el hash de los usuarios y sólo quiere ejecutar código específico para ese último usuario así que algo como

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

Gracias

+0

¿De verdad quieres decir un hash? Ordenar en un hash no siempre es confiable (dependiendo de cómo agregue cosas al hash y qué versión de ruby ​​está usando). Con un pedido no confiable, el "último" elemento no será consistente. El código en la pregunta y las respuestas que está obteniendo son más apropiados para una matriz o enumerable. Por ejemplo, los hashes no tienen los métodos 'each_with_index' o' last'. – Shadwell

+1

'Hash' se mezcla en Enumerable, por lo que tiene' each_with_index'. Incluso si las teclas hash no están ordenadas, este tipo de lógica aparece todo el tiempo cuando se renderizan vistas, donde el último elemento podría mostrarse de forma diferente independientemente de si es realmente "último" en cualquier sentido significativo de datos. – Raphomet

+0

Por supuesto, de acuerdo, los hashes sí tienen 'each_with_index', disculpas. Sí, puedo ver que saldría; 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 de una matriz. – Shadwell

Respuesta

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

El problema con esto es un condicional que se ejecuta cada vez. use '.last' fuera del ciclo. – bcackerman

+1

Acabo de agregar que si está iterando sobre un hash, debe escribirlo como: 'users.each_with_index do | (clave, valor), índice | #tu código final' – HUB

+0

Sé que no es del todo la misma pregunta, pero este código funciona mejor, creo que si quieres hacer algo para todos, pero el último usuario, así que estoy votando ya que eso era lo que estaba buscando – WhiteTiger

8

hizo que intentaste each_with_index?

users.each_with_index do |u, i| 
    if users.size-1 == i 
    #code for last items 
    end 
end 
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 
36

Si se trata de un bien/o situación, donde se va a aplicar un código a todos pero el último usuario y un código único para única el último usuario, una de la otra las soluciones pueden ser más apropiadas.

Sin embargo, parecen estar ejecutando el mismo código para todos los usuarios, y algunos código adicional para el último usuario. Si ese es el caso, esto parece más correcto, y más claramente declara su intención:

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

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

+1 por no necesitar un condicional, si es apropiado. (por supuesto, lo hice aquí) – Jeremy

+0

@meagar ¿no pasará este bucle a los usuarios dos veces? – ant

+0

@ant No, hay un bucle y una llamada a '.last' que no tiene nada que ver con el bucle. – meagar

17

Creo que un mejor enfoque es:

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

El problema con esta respuesta es que si el último usuario también aparece antes en la lista, el código condicional se llamará varias veces. – evanrmurphy

+0

tiene que usar 'u.equal? ​​(Users.last)', el método 'igual?' Compara el object_id, no el valor del objeto. Pero esto no funcionará con símbolos y números. –

0

No hay último método de hash para algunas versiones de rubí

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 
+0

¿Es una respuesta que mejora la respuesta de otra persona? Por favor, publique qué respuesta menciona el "último" método y qué propone para superar este problema. – Artemix

+0

Para las versiones de Ruby que no tienen un 'last', el conjunto de claves estará desordenado, por lo que esta respuesta arrojará resultados incorrectos/aleatorios de todos modos. – meagar

0

Otra solución es rescatar del StopIteration:

user_list = users.each 

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

Esta no es una buena solución a este problema. Las excepciones no se deben abusar para el control de flujo simple, son para situaciones * excepcionales *. – meagar

+0

@meagar Esto es realmente bastante genial. Estoy de acuerdo con que las excepciones ** no rescatadas ** o las que se deben pasar a un método más alto solo deberían ser para situaciones excepcionales. Sin embargo, esta es una manera clara (y aparentemente única) de obtener acceso al conocimiento nativo de ruby ​​de dónde termina un iterador. Si hay otra manera que, por supuesto, es preferible. El único problema real que tomaría con esto es que parece omitir y no hacer nada para el primer elemento. La solución que lo llevaría más allá del límite de clunkiness. – Adamantish

3

A veces me parece mejor separar la lógica en dos partes, una para todos los usuarios y otra para el último. Así que me gustaría hacer 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 
3

Puede utilizar @ enfoque de magro también para un bien/o situación, donde se va a aplicar algo de código para todos excepto el último usuario y un código único para sólo el ú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 necesita un condicional!

+0

@BeniBela No, [-1] es el último elemento. No hay [-0]. Entonces el penúltimo es [-2]. – coderuby

+0

'usuarios [0 ..- 2]' es correcto, como lo es 'users [0 ...- 1]'. Tenga en cuenta los diferentes operadores de rango '..' vs' ... ', vea http://stackoverflow.com/a/9690992/67834 –

Cuestiones relacionadas