Se eu tiver um loop como
users.each do |u|
#some code
end
Onde usuários é um hash de vários usuários. Qual é a lógica condicional mais fácil para ver se você está no último usuário no hash de usuários e deseja apenas executar um código específico para esse último usuário, algo como
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
fonte
fonte
each_with_index
oulast
.Hash
mistura em Enumerable, então temeach_with_index
. Mesmo que as chaves hash não sejam classificadas, esse tipo de lógica surge o tempo todo ao renderizar visualizações, onde o último item pode ser exibido de forma diferente, independentemente de ser realmente o "último" em qualquer sentido significativo para dados.each_with_index
, desculpas. Sim, posso ver que surgiria; apenas tentando esclarecer a questão. Pessoalmente, a melhor resposta para mim é o uso de,.last
mas isso não se aplica a um hash, apenas a um array.Respostas:
users.each_with_index do |u, index| # some code if index == users.size - 1 # code for the last user end end
fonte
.last
fora do loop.users.each_with_index do |(key, value), index| #your code end
Se for uma situação ou / ou, em que você está aplicando algum código a todos, exceto o último usuário e, em seguida, algum código exclusivo apenas ao último usuário, uma das outras soluções pode ser mais apropriada.
No entanto, parece que você está executando o mesmo código para todos os usuários e algum código adicional para o último usuário. Se for esse o caso, isso parece mais correto e afirma com mais clareza sua intenção:
users.each do |u| #code for everyone end users.last.do_stuff() # code for last user
fonte
.last
que não tem nada a ver com looping..last
. A coleção já está instanciada, basta um simples acesso a um array. Mesmo se a coleção ainda não tivesse sido carregada (como em, ainda era uma relação ActiveRecord não hidratada),last
ainda assim nunca faz loops para obter o último valor, isso seria extremamente ineficiente. Ele simplesmente modifica a consulta SQL para retornar o último registro. Dito isso, essa coleção já foi carregada pelo.each
, portanto, não há mais complexidade envolvida do que se você carregassex = [1,2,3]; x.last
.Acho que a melhor abordagem é:
users.each do |u| #code for everyone if u.equal?(users.last) #code for the last user end end
fonte
u.equal?(users.last)
, oequal?
método compara o object_id, não o valor do objeto. Mas isso não funcionará com símbolos e números.Você tentou
each_with_index
?users.each_with_index do |u, i| if users.size-1 == i #code for last items end end
fonte
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
fonte
Às vezes acho melhor separar a lógica em duas partes, uma para todos os usuários e outra para a última. Então, eu faria algo assim:
users[0...-1].each do |user| method_for_all_users user end method_for_all_users users.last method_for_last_user users.last
fonte
Você pode usar a abordagem de @ meager também para uma situação ou / ou, em que aplica algum código a todos, exceto o último usuário e, em seguida, algum código exclusivo apenas ao último usuário.
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
Dessa forma, você não precisa de uma condicional!
fonte
users[0..-2]
está correto, como estáusers[0...-1]
. Observe os diferentes operadores de alcance..
vs....
, consulte stackoverflow.com/a/9690992/67834Outra solução é resgatar de StopIteration:
user_list = users.each begin while true do user = user_list.next user.do_something end rescue StopIteration user.do_something end
fonte
StopIteration
foi projetado com a finalidade precisa de lidar com saídas de loop. Do livro de Matz: "Isso pode parecer incomum - uma exceção é gerada para uma condição de término esperada em vez de um evento inesperado e excepcional. (StopIteration
É um descendente deStandardError
eIndexError
; observe que é uma das únicas classes de exceção que não tem a palavra “Erro” em seu nome.) Ruby segue Python nesta técnica de iteração externa. (Mais ...)next
para um valor especial de fim de iteração e não há necessidade de chamar algum tipo denext?
predicado antes de chamarnext
. "loop do
tem um implícitorescue
ao encontrar umStopIteration
; ele é usado especificamente ao iterar externamente umEnumerator
objeto.loop do; my_enum.next; end
irá iterarmy_enum
e sair no final; não há necessidade de colocar umrescue StopIteration
lá. (Você precisa se usarwhile
ouuntil
.)Não há um último método para hash para algumas versões 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
fonte
last
, o conjunto de chaves será desordenado, então esta resposta retornará resultados errados / aleatórios de qualquer maneira.