Saya mencoba mengulangi ke belakang dengan menggunakan Range dan each
:
(4..0).each do |i|
puts i
end
==> 4..0
Iterasi melalui 0..4
penulisan angka. Di Rentang lain r = 4..0
tampaknya baik-baik saja r.first == 4
,, r.last == 0
.
Tampaknya aneh bagi saya bahwa konstruksi di atas tidak memberikan hasil yang diharapkan. Apa alasannya? Apa situasi ketika perilaku ini masuk akal?
.each
pernyataan tidak mengubah apa pun, tidak ada "hasil" yang dihitung untuk dikembalikan. Jika demikian, Ruby biasanya mengembalikan objek aslinya jika berhasil dannil
saat error. Ini memungkinkan Anda menggunakan ekspresi seperti ini sebagai kondisi padaif
pernyataan.Jawaban:
Rentang hanyalah itu: sesuatu yang ditentukan oleh awal dan akhir, bukan oleh isinya. "Iterasi" pada suatu rentang tidak benar-benar masuk akal dalam kasus umum. Pertimbangkan, misalnya, bagaimana Anda akan "mengulang" rentang yang dihasilkan oleh dua tanggal. Apakah Anda akan mengulang di siang hari? berdasarkan bulan? menurut tahun? menurut minggu? Itu tidak terdefinisi dengan baik. IMO, fakta bahwa itu diizinkan untuk rentang maju harus dilihat sebagai metode kenyamanan saja.
Jika Anda ingin mengulangi rentang seperti itu, Anda selalu dapat menggunakan
downto
:Berikut adalah beberapa pemikiran lain dari orang lain tentang mengapa sulit untuk mengizinkan iterasi dan secara konsisten menangani rentang terbalik.
sumber
.each
ada berlebihan,5.downto(1) { |n| puts n }
bekerja dengan baik. Juga, alih-alih semua hal terakhir yang terakhir, lakukan saja(6..10).reverse_each
.= f.select :model_year, (Time.zone.now.year + 1).downto(Time.zone.now.year - 100).to_a
Bagaimana dengan
(0..1).reverse_each
yang mengulang rentang ke belakang?sumber
(Date.today.beginning_of_year..Date.today.yesterday).reverse_each
Terima kasihIterasi pada rentang di Ruby dengan
each
memanggilsucc
metode pada objek pertama dalam rentang tersebut.Dan 5 berada di luar jangkauan.
Anda dapat mensimulasikan iterasi terbalik dengan peretasan ini:
John menunjukkan bahwa ini tidak akan berhasil jika span 0. Ini akan:
Tidak bisa mengatakan saya sangat menyukai salah satu dari mereka karena mereka agak mengaburkan maksudnya.
sumber
Menurut buku "Programming Ruby", objek Range menyimpan dua endpoint dari range dan menggunakan
.succ
anggota untuk menghasilkan nilai antara. Bergantung pada jenis tipe data yang Anda gunakan dalam rentang Anda, Anda selalu dapat membuat subkelasInteger
dan mendefinisikan ulang.succ
anggotanya sehingga berfungsi seperti iterator terbalik (Anda mungkin juga ingin mendefinisikan ulang.next
juga).Anda juga dapat mencapai hasil yang Anda cari tanpa menggunakan Range. Coba ini:
Ini akan melangkah dari 4 menjadi 0 dalam langkah -1. Namun, saya tidak tahu apakah ini akan berhasil untuk apa pun kecuali argumen Integer.
sumber
Cara lainnya adalah
(1..10).to_a.reverse
sumber
Anda bahkan dapat menggunakan
for
loop:yang mencetak:
sumber
jika daftarnya tidak terlalu besar. saya pikir
[*0..4].reverse.each { |i| puts i }
cara paling sederhana.sumber
Seperti yang dikatakan bta, alasannya adalah
Range#each
mengirimsucc
ke awalnya, lalu ke hasilsucc
panggilan itu, dan seterusnya sampai hasilnya lebih besar dari nilai akhir. Anda tidak bisa mendapatkan dari 4 ke 0 dengan meneleponsucc
, dan pada kenyataannya Anda sudah memulai lebih dari yang terakhir.sumber
Saya menambahkan satu sama lain kemungkinan bagaimana mewujudkan iterasi atas Range terbalik. Saya tidak menggunakannya, tapi itu kemungkinan. Agak berisiko untuk menambal objek inti ruby monyet.
sumber
Ini berhasil untuk kasus penggunaan malas saya
sumber
OP menulis
bukan 'Bisakah itu dilakukan?' tetapi untuk menjawab pertanyaan yang tidak ditanyakan sebelum sampai pada pertanyaan yang sebenarnya ditanyakan:
Karena reverse_each diklaim untuk membangun seluruh array, downto jelas akan lebih efisien. Fakta bahwa seorang perancang bahasa bahkan dapat mempertimbangkan untuk mengimplementasikan hal-hal seperti itu agak terkait dengan jawaban atas pertanyaan sebenarnya seperti yang ditanyakan.
Untuk menjawab pertanyaan seperti yang sebenarnya ditanyakan ...
Alasannya karena Ruby adalah bahasa yang selalu mengejutkan. Beberapa kejutan memang menyenangkan, tetapi ada banyak perilaku yang benar-benar rusak. Meskipun beberapa dari contoh berikut ini dikoreksi oleh rilis yang lebih baru, masih banyak lainnya, dan mereka tetap sebagai dakwaan pada pola pikir dari desain aslinya:
menghasilkan "" tetapi
menghasilkan
Anda mungkin mengharapkan << dan mendorong menjadi sama untuk menambahkan ke array, tapi
Anda mungkin berharap 'grep' berperilaku seperti baris perintah Unix yang setara, tetapi ia tidak === cocok dengan not = ~, terlepas dari namanya.
Berbagai metode secara tidak terduga merupakan alias untuk satu sama lain, jadi Anda harus mempelajari banyak nama untuk hal yang sama - misalnya
find
dandetect
- bahkan jika Anda memang menyukai kebanyakan pengembang dan hanya menggunakan satu atau yang lain. Hal yang sama berlaku untuksize
,,count
danlength
, kecuali untuk kelas yang mendefinisikan masing-masing secara berbeda, atau tidak mendefinisikan satu atau dua sama sekali.Kecuali seseorang telah menerapkan sesuatu yang lain - seperti metode inti
tap
telah didefinisikan ulang di berbagai pustaka otomatisasi untuk menekan sesuatu di layar. Semoga berhasil mencari tahu apa yang terjadi, terutama jika beberapa modul yang dibutuhkan oleh modul lain telah menggunakan modul lain untuk melakukan sesuatu yang tidak terdokumentasi.Objek variabel lingkungan, ENV tidak mendukung 'merge', jadi Anda harus menulis
Sebagai bonus, Anda bahkan dapat mendefinisikan ulang konstanta Anda atau orang lain jika Anda berubah pikiran tentang apa yang seharusnya.
sumber
grep
dengan cara apa pun, bentuk atau bentuk terkait dengan fakta bahwa iterasi pada rentang kosong adalah tanpa operasi. Saya juga tidak melihat bagaimana fakta bahwa iterasi pada rentang kosong adalah no-op dalam bentuk atau bentuk apapun yang "mengejutkan tanpa henti" dan "benar-benar rusak".Bagi saya cara yang paling sederhana adalah:
Cara lain untuk mengulang pencacahan:
sumber