2012-01-11 20 views

Respuesta

44

La forma más sencilla de hacerlo es utilizar downto

5.downto(1) do |i| puts i end 
+0

Muy bien, gracias Derek! – larryzhao

+2

Y en las versiones modernas de Ruby, puede hacer 'x = 5.downto (1)' y pasar 'x' alrededor como una variable. –

+0

Agradable. un rango maneja un bloque como un iterador automáticamente. No es necesario llamar explícitamente a '.each' – ahnbizcad

20

rangos utilizan <=> para determinar si una iteración ha terminado; 5 <=> 1 == 1 (mayor que), por lo que se hace antes de que comience. Incluso si no lo hicieran, los intervalos se repiten usando succ; 5.succ es 6, todavía no tuvo suerte. Un rango de step no puede ser negativo, por lo que tampoco funcionará.

Devuelve el rango porque each devuelve el nombre que recibió. Use downto si es la funcionalidad en sí misma que está buscando, de lo contrario, lo anterior responde su pregunta real con respecto al "por qué".

+0

Muy buena explicación, ahora los entiendo a todos. – larryzhao

1

Esto ni siquiera tiene nada que ver con Ruby, es simplemente matemática básica: el rango que comienza con 5 y termina con 1 está vacío. No hay nada por lo cual iterar.

+2

Sí, pero ¿por qué Ruby no va "espere un momento, 1 es menos de 5, vamos en reversa"? –

+6

ruby ​​es muy fácil de usar, por lo que sería completamente razonable esperar que funcione. – ahnbizcad

+1

@AndrewGrimm: porque Ruby no puede decirlo. El protocolo de rango no requiere que el valor correcto responda a '<=>', solo a la izquierda. –

0

Porque Ruby solo hace lo que se le dice, no lo que mean.

No se puede decir si desea ir en reversa (es decir, 5, 4, 3, 2, 1), o si realmente solo desea los números a partir de 5 que son menores o iguales a 1. Es teóricamente es posible que alguien quiera lo último, y como Ruby no puede decir lo que realmente quiere, le irá bien a este último.

+0

números a partir de 5 que son menores o iguales a 1 – Neeraj

+1

que no fueron muy constructivos. – Hamdan

+1

@Hamdan ¿Puedes explicar por qué mi respuesta no es constructiva? No llamo a nadie idiota, solo estoy explicando que Ruby no funciona de la manera que el OP esperaría. –

3

Se puede ampliar fácilmente la clase Range, en particular, la cada método, para que sea compatible con tanto ascendente como descendente rangos:

class Range 
    def each 
    if self.first < self.last 
     self.to_s=~(/\.\.\./) ? last = self.last-1 : last = self.last 
     self.first.upto(last) { |i| yield i} 
    else 
     self.to_s=~(/\.\.\./) ? last = self.last+1 : last = self.last 
     self.first.downto(last) { |i| yield i } 
    end 
    end 
end 

A continuación, el siguiente código llevará a cabo del mismo modo que había esperar:

(0..10).each { |i| puts i} 
(0...10).each { |i| puts i} 
(10..0).each { |i| puts i} 
(10...0).each { |i| puts i} 
+1

Bien codificado. Un riesgo al tomar este enfoque es que es posible que tenga las bibliotecas existentes en la cual el programador supone que un rango hacia atrás no tendría iteraciones, y al hacer este cambio que romper esa asunción y introducir errores en la ejecución de la biblioteca. Imagine que los límites izquierdo y derecho están representados por variables, x e y, en lugar de Fixnums constantes. En tal caso, el programador puede confiar en el comportamiento de rango "normal". Este es un riesgo típico cuando se arregla una clase en Ruby. –

Cuestiones relacionadas