signo - ruby tutorial
escapando la iteración de.each{} temprano en Ruby (8)
código:
c = 0
items.each { |i|
puts i.to_s
# if c > 9 escape the each iteration early - and do not repeat
c++
}
Quiero tomar los primeros 10 elementos y luego abandonar el ciclo "cada".
¿Con qué reemplazo la línea comentada? hay un mejor enfoque? algo más Ruby idiomático?
¿Esto se ve como lo que quieres?
10.times { |i|
puts items[i].to_s
}
Fue preguntado:
Quiero tomar los primeros 10 elementos y luego abandonar el ciclo "cada".
Utilice throw and catch para lograr esto, con algunos cambios en el ejemplo:
catch(:done) do
c = 0
collected = []
items.each do |item|
collected << item
throw(:done, collected) if c == 9 # started at 0
c += 1
end
collected # if the list is less than 10 long, return what was collected
end
Simplemente throw la etiqueta :done con collected y la catch que está esperando :done volverá collected .
Y para "ruby" esto un poco:
catch(:done) do
items.inject([]) do |collected, item|
throw(:done, collected) if collected.size == 10
collected << item # collected gets returned here and populates the first argument of this block
end
end
No sé por qué algunas personas se niegan a usar inject y usar reduce (son equivalentes) cuando claramente el conjunto vacío dado a la inject([]) se está inyectando con el item s. De todos modos, la inject devolverá collected si hay menos de 10 elementos.
La mayoría de las respuestas intentan responder a lo que podría ser la intención de la pregunta en lugar de lo que se preguntó y items.take(10) tiene perfecto sentido en ese caso. Pero me imagino que quiero tomar los primeros artículos que encajan dentro de mi presupuesto de $ 100. Entonces puedes simplemente:
catch(:done) do
items.inject({items: [], budget: 100}) do |ledger, item|
remainder = ledger[:budget] - item.price
if remainder < 0
throw(:done, ledger)
else
ledger.tap do |this|
this[:items] << item
this[:budget] = remainder
end # tap just returns what is being tapped into, in this case, ledger
end
end
end
No hay operador ++ en Ruby. También es una convención usar do y end para bloques multilínea. Modificar los rendimientos de su solución:
c = 0
items.each do |i|
puts i.to_s
break if c > 9
c += 1
end
O también:
items.each_with_index do |i, c|
puts i.to_s
break if c > 9
end
Ver each_with_index y también programar Ruby Break, Rehacer y Siguiente .
Actualización: la respuesta de Chuck con rangos es más similar a Ruby, y la respuesta de nimrodm con take es aún mejor.
Otra opción sería
items.first(10).each do |i|
puts i.to_s
end
Eso me resulta un poco más fácil de leer que romper un iterador, y primero solo devolverá tantos elementos como estén disponibles si no son suficientes.
Otra variante:
puts items.first(10)
Tenga en cuenta que esto funciona bien con matrices de menos de 10 elementos:
>> nums = (1..5).to_a
=> [1, 2, 3, 4, 5]
>> puts nums.first(10)
1
2
3
4
5
(Una nota más, mucha gente está ofreciendo alguna forma de puts i.to_s , pero en tal caso, no es .to_s redundante? .to_s llamará automáticamente .to_s en una cadena para imprimirlo, pensé .to_s si quisiera decir puts ''A'' + i.to_s o similares.)
Si bien la solución de break funciona, creo que un enfoque más funcional realmente se adapta a este problema. Desea take los primeros 10 elementos e imprimirlos, así que intente
items.take(10).each { |i| puts i.to_s }
break funciona para escaparse temprano de un ciclo, pero es más idiomático simplemente hacer items[0..9].each {|i| puts i} items[0..9].each {|i| puts i} . (Y si todo lo que hace es, literalmente, imprimir los elementos sin ningún cambio, puede simplemente puts items[0..9] ).
items.each_with_index { |i, c| puts i and break if c <= 9 }