Ich habe versucht, mit einem Bereich rückwärts zu iterieren und each
:
(4..0).each do |i|
puts i
end
==> 4..0
Iteration durch 0..4
schreibt die Zahlen. Auf der anderen Strecke r = 4..0
scheint in Ordnung zu sein r.first == 4
, r.last == 0
.
Es scheint mir seltsam, dass das obige Konstrukt nicht das erwartete Ergebnis liefert. Was ist der Grund dafür? In welchen Situationen ist dieses Verhalten angemessen?
.each
Anweisung nichts geändert hat, kann kein berechnetes "Ergebnis" zurückgegeben werden. In diesem Fall gibt Ruby normalerweise das ursprüngliche Objekt bei Erfolg undnil
Fehler zurück. Auf diese Weise können Sie solche Ausdrücke als Bedingungen für eineif
Anweisung verwenden.Antworten:
Ein Bereich ist genau das: etwas, das durch seinen Anfang und sein Ende definiert wird, nicht durch seinen Inhalt. Das "Iterieren" über einen Bereich ist im Allgemeinen nicht wirklich sinnvoll. Stellen Sie sich zum Beispiel vor, wie Sie über den Bereich "iterieren" würden, der durch zwei Daten erzeugt wird. Würden Sie tagsüber iterieren? nach Monaten? Pro Jahr? pro Woche? Es ist nicht gut definiert. IMO, die Tatsache, dass es für Vorwärtsbereiche erlaubt ist, sollte nur als bequeme Methode angesehen werden.
Wenn Sie über einen solchen Bereich rückwärts iterieren möchten, können Sie immer Folgendes verwenden
downto
:Hier sind einige weitere Gedanken von anderen darüber, warum es schwierig ist, sowohl Iteration zuzulassen als auch konsequent mit umgekehrten Bereichen umzugehen.
quelle
.each
gibt es überflüssig,5.downto(1) { |n| puts n }
funktioniert gut. Anstelle all dieser ersten Dinge tun Sie es einfach(6..10).reverse_each
.= f.select :model_year, (Time.zone.now.year + 1).downto(Time.zone.now.year - 100).to_a
Wie wäre es
(0..1).reverse_each
, wenn der Bereich rückwärts iteriert?quelle
(Date.today.beginning_of_year..Date.today.yesterday).reverse_each
DankeDurch Iterieren über einen Bereich in Ruby mit
each
ruft diesucc
Methode für das erste Objekt im Bereich auf.Und 5 liegt außerhalb des Bereichs.
Mit diesem Hack können Sie die umgekehrte Iteration simulieren:
John wies darauf hin, dass dies nicht funktionieren wird, wenn es sich über 0 erstreckt. Dies würde:
Ich kann nicht sagen, dass ich einen von ihnen wirklich mag, weil sie die Absicht irgendwie verdunkeln.
quelle
Gemäß dem Buch "Programming Ruby" speichert das Range-Objekt die beiden Endpunkte des Bereichs und
.succ
generiert mit dem Member die Zwischenwerte. Abhängig davon, welche Art von Datentyp Sie in Ihrem Bereich verwenden, können Sie jederzeit eine Unterklasse von erstellen und das ElementInteger
neu definieren,.succ
sodass es sich wie ein umgekehrter Iterator verhält (wahrscheinlich möchten Sie es auch neu definieren.next
).Sie können die gewünschten Ergebnisse auch erzielen, ohne einen Bereich zu verwenden. Versuche dies:
Dies wird in Schritten von -1 von 4 auf 0 erhöht. Ich weiß jedoch nicht, ob dies für etwas anderes als Integer-Argumente funktioniert.
quelle
Ein anderer Weg ist
(1..10).to_a.reverse
quelle
Sie können sogar eine
for
Schleife verwenden:welche druckt:
quelle
wenn die Liste nicht so groß ist. Ich denke,
[*0..4].reverse.each { |i| puts i }
ist der einfachste Weg.quelle
Wie BTA gesagt, ist der Grund dafür , dass
Range#each
sendetsucc
an seinem Anfang, dann auf das Ergebnis diesessucc
Anrufs, und so weiter , bis das Ergebnis größer als der Endwert. Sie können nicht von 4 auf 0 kommen, indem Sie anrufensucc
, und tatsächlich beginnen Sie bereits größer als das Ende.quelle
Ich füge einander eine Möglichkeit hinzu, wie man eine Iteration über den umgekehrten Bereich realisiert. Ich benutze es nicht, aber es ist eine Möglichkeit. Es ist ein bisschen riskant, Rubinkernobjekte mit Affenflecken zu versehen.
quelle
Dies funktionierte für meinen faulen Anwendungsfall
quelle
Das OP schrieb
nicht 'Kann es gemacht werden?' aber um die Frage zu beantworten, die nicht gestellt wurde, bevor man zu der Frage kam, die tatsächlich gestellt wurde:
Da reverse_each angeblich ein ganzes Array erstellt, wird Downto eindeutig effizienter. Die Tatsache, dass ein Sprachdesigner sogar in Betracht ziehen könnte, solche Dinge zu implementieren, hängt mit der Antwort auf die eigentliche Frage zusammen.
Um die tatsächlich gestellte Frage zu beantworten ...
Der Grund ist, dass Ruby eine unendlich überraschende Sprache ist. Einige Überraschungen sind angenehm, aber es gibt viele Verhaltensweisen, die regelrecht gebrochen sind. Auch wenn einige dieser folgenden Beispiele durch neuere Versionen korrigiert wurden, gibt es viele andere, und sie bleiben als Anklage gegen die Denkweise des ursprünglichen Designs:
führt zu "" aber
führt zu
Sie würden wahrscheinlich erwarten, dass << und push beim Anhängen an Arrays gleich sind, aber
Sie würden wahrscheinlich erwarten, dass sich 'grep' wie sein Unix-Befehlszeilenäquivalent verhält, aber es stimmt trotz seines Namens nicht = ~ überein.
Verschiedene Methoden sind unerwartet Aliase für einander, daher müssen Sie mehrere Namen für dasselbe lernen - z. B.
find
unddetect
- auch wenn Sie die meisten Entwickler mögen und immer nur den einen oder anderen verwenden. Ähnliches gilt fürsize
,,count
undlength
, mit Ausnahme von Klassen, die jeweils unterschiedlich oder gar nicht ein oder zwei definieren.Es sei denn, jemand hat etwas anderes implementiert - wie die
tap
Kernmethode in verschiedenen Automatisierungsbibliotheken neu definiert wurde, um etwas auf den Bildschirm zu drücken. Viel Glück beim Herausfinden, was los ist, insbesondere wenn ein Modul, das von einem anderen Modul benötigt wird, ein weiteres Modul aktiviert hat, um etwas Undokumentiertes zu tun.Das Umgebungsvariablenobjekt ENV unterstützt 'Zusammenführen' nicht, daher müssen Sie schreiben
Als Bonus können Sie sogar die Konstanten Ihrer oder einer anderen Person neu definieren, wenn Sie Ihre Meinung darüber ändern, was sie sein sollen.
quelle
grep
in irgendeiner Weise, Form oder Gestalt mit der Tatsache zusammenhängt, dass das Iterieren über einen leeren Bereich ein No-Op ist. Ich sehe auch nicht, wie die Tatsache, dass das Iterieren über einen leeren Bereich ein No-Op ist, in irgendeiner Form "endlos überraschend" und "geradezu gebrochen" ist.Für mich ist der einfachste Weg:
Eine andere Möglichkeit, die Aufzählung zu wiederholen:
quelle