Intenté iterar hacia atrás con el uso de un Range y each
:
(4..0).each do |i|
puts i
end
==> 4..0
La iteración 0..4
escribe los números. Por otro rango r = 4..0
parece estar bien, r.first == 4
, r.last == 0
.
Me parece extraño que la construcción anterior no produzca el resultado esperado. ¿Cuál es la razón de eso? ¿Cuáles son las situaciones en las que este comportamiento es razonable?
.each
declaración no modificó nada, no hay ningún "resultado" calculado para devolver. Cuando este es el caso, Ruby normalmente devuelve el objeto original en caso de éxito ynil
error. Esto le permite usar expresiones como esta como condiciones en unaif
declaración.Respuestas:
Un rango es solo eso: algo definido por su inicio y final, no por su contenido. "Iterar" en un rango no tiene sentido en un caso general. Considere, por ejemplo, cómo "iteraría" sobre el rango producido por dos fechas. ¿Repetirías de día? ¿Por mes? ¿por año? ¿por semana? No está bien definido. En mi opinión, el hecho de que esté permitido para rangos de avance debe verse solo como un método de conveniencia.
Si desea iterar hacia atrás en un rango como ese, siempre puede usar
downto
:Aquí hay algunos pensamientos más de otros sobre por qué es difícil permitir la iteración y tratar consistentemente con rangos inversos.
fuente
.each
no es redundante,5.downto(1) { |n| puts n }
funciona bien. Además, en lugar de todo lo primero, lo último, hazlo(6..10).reverse_each
.= f.select :model_year, (Time.zone.now.year + 1).downto(Time.zone.now.year - 100).to_a
¿Qué tal
(0..1).reverse_each
que itera el rango al revés?fuente
(Date.today.beginning_of_year..Date.today.yesterday).reverse_each
GraciasIterando sobre un rango en Ruby con
each
llamadas alsucc
método en el primer objeto en el rango.Y 5 está fuera del rango.
Puede simular la iteración inversa con este truco:
John señaló que esto no funcionará si se extiende por 0. Esto:
No puedo decir que realmente me guste ninguno de ellos porque oscurecen la intención.
fuente
Según el libro "Programming Ruby", el objeto Range almacena los dos puntos finales del rango y usa el
.succ
miembro para generar los valores intermedios. Dependiendo del tipo de tipo de datos que esté usando en su rango, siempre puede crear una subclaseInteger
y volver a definir el.succ
miembro para que actúe como un iterador inverso (probablemente también desee volver a definirlo.next
).También puede lograr los resultados que busca sin utilizar un rango. Prueba esto:
Esto pasará de 4 a 0 en pasos de -1. Sin embargo, no sé si esto funcionará para algo excepto para los argumentos Integer.
fuente
Otra forma es
(1..10).to_a.reverse
fuente
Incluso puedes usar un
for
bucle:que imprime:
fuente
si la lista no es tan grande. Creo que
[*0..4].reverse.each { |i| puts i }
es la forma más sencilla.fuente
Como dijo bta, la razón es que
Range#each
envíasucc
a su inicio, luego al resultado de esasucc
llamada, y así sucesivamente hasta que el resultado sea mayor que el valor final. No puedes pasar de 4 a 0 llamandosucc
, y de hecho ya comienzas más que el final.fuente
Agrego otra posibilidad de cómo realizar la iteración sobre el rango inverso. No lo uso, pero es una posibilidad. Es un poco arriesgado parchear objetos con núcleo de rubí.
fuente
Esto funcionó para mi caso de uso perezoso
fuente
El OP escribió
no '¿Se puede hacer?' pero para responder la pregunta que no se hizo antes de llegar a la pregunta que realmente se hizo:
Dado que se afirma que reverse_each crea una matriz completa, es evidente que downto será más eficiente. El hecho de que un diseñador de idiomas pueda incluso considerar implementar cosas como esa se relaciona un poco con la respuesta a la pregunta real tal como se le preguntó.
Para responder a la pregunta como se hizo realmente ...
La razón es que Ruby es un lenguaje infinitamente sorprendente. Algunas sorpresas son agradables, pero hay muchos comportamientos que están rotos. Incluso si algunos de estos ejemplos siguientes se corrigen con versiones más recientes, hay muchos otros y permanecen como acusaciones en la mentalidad del diseño original:
da como resultado "" pero
resultados en
Probablemente esperaría que << y push sea lo mismo para agregar a matrices, pero
Probablemente esperaría que 'grep' se comporte como su equivalente en la línea de comandos de Unix, pero no coincide === con = ~, a pesar de su nombre.
Varios métodos tienen alias inesperadamente entre sí, por lo que debe aprender varios nombres para lo mismo, por ejemplo,
find
ydetect
, incluso si le gusta la mayoría de los desarrolladores y solo usa uno u otro. Lo mismo ocurre consize
,count
ylength
, excepto para las clases que definen cada una de manera diferente, o que no definen una o dos en absoluto.A menos que alguien haya implementado algo más, como que el método principal
tap
se haya redefinido en varias bibliotecas de automatización para presionar algo en la pantalla. Buena suerte averiguando lo que está pasando, especialmente si algún módulo requerido por otro módulo ha engañado a otro módulo para hacer algo indocumentado.El objeto de la variable de entorno, ENV no admite 'fusionar', por lo que debe escribir
Como beneficio adicional, incluso puede redefinir sus constantes o las de otra persona si cambia de opinión sobre lo que deberían ser.
fuente
grep
está relacionado de alguna manera, forma o forma con el hecho de que iterar sobre un rango vacío es una no operación. Tampoco veo cómo el hecho de que iterar sobre un rango vacío es una operación no operativa es de alguna manera "infinitamente sorprendente" y "completamente roto".En cuanto a mí, la forma más sencilla es:
Otra forma de iterar para la enumeración:
fuente