tutorial signo punteros programas metodo initialize identificadores hechos ejemplos ruby loops iterator enumerator

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



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 }