J'ai essayé d'itérer en arrière en utilisant une plage et each
:
(4..0).each do |i|
puts i
end
==> 4..0
L'itération par 0..4
écrit les nombres. D'autre plage r = 4..0
semble être ok, r.first == 4
, r.last == 0
.
Il me semble étrange que la construction ci-dessus ne donne pas le résultat attendu. Quelle en est la raison? Quelles sont les situations où ce comportement est raisonnable?
.each
instruction n'a rien modifié, il n'y a aucun "résultat" calculé à renvoyer. Dans ce cas, Ruby renvoie généralement l'objet d'origine en cas de succès etnil
en cas d'erreur. Cela vous permet d'utiliser des expressions comme celle-ci comme conditions sur uneif
instruction.Réponses:
Une plage n'est que cela: quelque chose défini par son début et sa fin, pas par son contenu. «Itérer» sur une plage n'a pas vraiment de sens dans un cas général. Considérez, par exemple, comment vous «itéreriez» sur la plage produite par deux dates. Souhaitez-vous itérer par jour? par mois? par année? par semaine? Ce n'est pas bien défini. OMI, le fait qu'il soit autorisé pour les plages avant doit être considéré comme une méthode de commodité uniquement.
Si vous souhaitez effectuer une itération en arrière sur une plage comme celle-ci, vous pouvez toujours utiliser
downto
:Voici quelques réflexions d'autres personnes sur les raisons pour lesquelles il est difficile à la fois d'autoriser l'itération et de gérer systématiquement les plages inversées.
la source
.each
là est redondant,5.downto(1) { |n| puts n }
fonctionne très bien. Aussi, au lieu de tous ces trucs r.first r.last, faites-le(6..10).reverse_each
.= f.select :model_year, (Time.zone.now.year + 1).downto(Time.zone.now.year - 100).to_a
Que diriez-vous de
(0..1).reverse_each
laquelle itère la plage à l'envers?la source
(Date.today.beginning_of_year..Date.today.yesterday).reverse_each
MerciItérer sur une plage en Ruby avec
each
appelle lasucc
méthode sur le premier objet de la plage.Et 5 est en dehors de la plage.
Vous pouvez simuler une itération inverse avec ce hack:
John a souligné que cela ne fonctionnera pas s'il s'étend sur 0. Cela:
Je ne peux pas dire que j'aime vraiment l'un d'entre eux parce qu'ils obscurcissent en quelque sorte l'intention.
la source
Selon le livre "Programming Ruby", l'objet Range stocke les deux extrémités de la plage et utilise le
.succ
membre pour générer les valeurs intermédiaires. Selon le type de type de données que vous utilisez dans votre plage, vous pouvez toujours créer une sous-classeInteger
et redéfinir le.succ
membre afin qu'il agisse comme un itérateur inversé (vous voudrez probablement également redéfinir.next
).Vous pouvez également obtenir les résultats que vous recherchez sans utiliser de plage. Essaye ça:
Cela passera de 4 à 0 par incréments de -1. Cependant, je ne sais pas si cela fonctionnera pour autre chose que les arguments Integer.
la source
Une autre façon est
(1..10).to_a.reverse
la source
Vous pouvez même utiliser une
for
boucle:qui imprime:
la source
si la liste n'est pas si grande. je pense que
[*0..4].reverse.each { |i| puts i }
c'est le moyen le plus simple.la source
Comme bta l'a dit, la raison est que cela
Range#each
envoiesucc
à son début, puis au résultat de cetsucc
appel, et ainsi de suite jusqu'à ce que le résultat soit supérieur à la valeur finale. Vous ne pouvez pas passer de 4 à 0 en appelantsucc
, et en fait vous commencez déjà plus grand que la fin.la source
J'ajoute une autre possibilité de réaliser une itération sur une plage inversée. Je ne l'utilise pas, mais c'est une possibilité. Il est un peu risqué de monkey patch ruby core objects.
la source
Cela a fonctionné pour mon cas d'utilisation paresseux
la source
L'OP a écrit
pas «Peut-il être fait? mais pour répondre à la question qui n'a pas été posée avant d'arriver à la question qui a été réellement posée:
Puisque reverse_each est censé créer un tableau entier, downto sera clairement plus efficace. Le fait qu'un concepteur de langage puisse même envisager de mettre en œuvre des choses comme celles-là est un peu lié à la réponse à la question réelle posée.
Pour répondre à la question telle qu'elle est réellement posée ...
La raison en est que Ruby est un langage infiniment surprenant. Certaines surprises sont agréables, mais il y a beaucoup de comportements qui sont carrément cassés. Même si certains de ces exemples suivants sont corrigés par des versions plus récentes, il y en a beaucoup d'autres, et ils restent comme des accusations sur l'état d'esprit de la conception originale:
donne "" mais
résulte en
Vous vous attendriez probablement à ce que << et push soient les mêmes pour l'ajout aux tableaux, mais
Vous vous attendriez probablement à ce que «grep» se comporte comme son équivalent en ligne de commande Unix, mais il correspond === non = ~, malgré son nom.
Diverses méthodes sont inopinément des alias l'une pour l'autre, vous devez donc apprendre plusieurs noms pour la même chose - par exemple
find
etdetect
- même si vous aimez la plupart des développeurs et n'utilisez jamais que l'un ou l'autre. Il en va de même poursize
,count
etlength
, à l' exception des classes qui définissent différemment chacun, ou ne définissent pas un ou deux du tout.À moins que quelqu'un n'ait implémenté autre chose - comme la méthode principale
tap
a été redéfinie dans diverses bibliothèques d'automatisation pour appuyer sur quelque chose à l'écran. Bonne chance pour découvrir ce qui se passe, surtout si un module requis par un autre module a monkey encore un autre module pour faire quelque chose de non documenté.L'objet de variable d'environnement, ENV ne prend pas en charge 'merge', vous devez donc écrire
En prime, vous pouvez même redéfinir vos constantes ou celles de quelqu'un d'autre si vous changez d'avis sur ce qu'elles devraient être.
la source
grep
est de quelque manière que ce soit, forme ou forme lié au fait que l'itération sur une plage vide est un non-op. Je ne vois pas non plus en quoi le fait que l'itération sur une plage vide soit un non-op est en aucune façon une forme ou une forme "infiniment surprenante" et "carrément cassée".Quant à moi, le moyen le plus simple est:
Une autre façon d'itérer pour l'énumération:
la source