Perulangan dan iterator

while, until, loop, serta iterator times, each, dan upto yang menjadi gaya Ruby.

Daftar isi

Perulangan menjalankan sekumpulan pernyataan berulang kali, baik selama sebuah syarat terpenuhi maupun untuk setiap elemen dalam sebuah koleksi. Topik ini membahas while, until, dan loop untuk perulangan berbasis kondisi, kemudian iterator times, upto, downto, step, dan each yang menjadi gaya khas Ruby. Setelah membacanya, pemilihan bentuk perulangan untuk kasus berbasis hitungan maupun berbasis koleksi dapat dilakukan dengan pertimbangan yang tepat, lengkap dengan cara menghentikannya.

while dan until#

Pernyataan while mengulang badannya selama kondisi bernilai benar, dan kondisi dinilai sebelum setiap iterasi dimulai. Karena penilaian terjadi sebelum badan, badan tidak pernah dijalankan apabila kondisi langsung palsu sejak awal. Variabel yang terlibat dalam kondisi harus berubah di dalam badan, karena perubahan itulah yang membuat perulangan berakhir.

ruby while mengulang selama kondisi benar
sisa = 3
while sisa > 0
  puts "Menunggu #{sisa} menit"
  sisa -= 1
end
puts "Selesai menunggu"
text Keluaran
Menunggu 3 menit
Menunggu 2 menit
Menunggu 1 menit
Selesai menunggu

Alur pemeriksaan kondisi dan pengulangannya digambarkan pada diagram berikut.

mulaikondisi benar?yabadan perulanganulangitidakkode setelah perulanganselesai
Alur perulangan while dengan kondisi yang dinilai sebelum setiap iterasi

Kata kunci until adalah kebalikan dari while, yaitu mengulang badan sampai kondisinya bernilai benar. Bentuk ini nyaman untuk kondisi yang dinyatakan sebagai tujuan, misalnya menunggu sensor mencapai suhu tertentu. Contoh berikut menaikkan suhu satu derajat setiap iterasi hingga target tercapai.

ruby until mengulang sampai kondisi benar
suhu = 24
until suhu >= 26
  puts "Suhu #{suhu} derajat, menunggu pemanasan"
  suhu += 1
end
puts "Suhu target tercapai: #{suhu}"
text Keluaran
Suhu 24 derajat, menunggu pemanasan
Suhu 25 derajat, menunggu pemanasan
Suhu target tercapai: 26

loop, break, dan next#

Metode loop mengulang blok (block) tanpa syarat apa pun. Blok adalah potongan kode di antara do dan end yang diserahkan ke metode untuk dijalankan. Perulangannya hanya berakhir melalui break. Kata kunci break menghentikan perulangan sepenuhnya, sedangkan next melompati sisa badan dan berlanjut ke iterasi berikutnya. Kombinasi keduanya memungkinkan perulangan berhenti menurut keadaan di tengah badan, bukan hanya menurut kondisi awal.

ruby loop dengan break dan next pada antrean loket
nomor_antrian = 0
loop do
  nomor_antrian += 1
  break if nomor_antrian > 4
  next if nomor_antrian == 2
  puts "Melayani nomor #{nomor_antrian}"
end
text Keluaran
Melayani nomor 1
Melayani nomor 3
Melayani nomor 4

Nomor 2 dilewati oleh next tanpa mencetak apa pun, sedangkan nomor 5 tidak pernah tercetak karena break berjalan lebih dulu. Posisi break sebelum next menjamin perulangan berhenti walaupun syarat next juga terpenuhi. Urutan kedua kata kunci ini perlu diperiksa setiap kali keduanya digunakan bersama.

Iterator times, upto, dan kerabatnya#

Bilangan di Ruby menyediakan iterator, yaitu metode yang menjalankan blok secara berulang dengan jumlah langkah yang pasti. Metode times mengulang blok sebanyak nilai bilangannya dan menyampaikan indeks berjalan ke variabel blok. Metode upto, downto, dan step mengulang dari nilai awal menuju nilai akhir menurut arah dan panjang langkahnya.

ruby times mengulang dengan indeks dari nol
3.times do |nomor|
  puts "Piket hari ke-#{nomor + 1}"
end
text Keluaran
Piket hari ke-1
Piket hari ke-2
Piket hari ke-3

Indeks yang disampaikan times dimulai dari nol, sehingga penomoran yang lazim dibaca manusia, seperti hari ke-1, memerlukan penjumlahan nomor + 1 di dalam interpolasi. Kebiasaan ini mengikuti konvensi pengindeksan Ruby secara umum. Contoh berikut memadukan tiga iterator bilangan dalam satu program.

ruby upto, downto, dan step pada Integer
1.upto(3) { |n| puts "Hari #{n}" }
5.downto(3) { |n| puts "Hitung mundur #{n}" }
0.step(12, 4) { |n| puts "Pemeriksaan menit #{n}" }
text Keluaran
Hari 1
Hari 2
Hari 3
Hitung mundur 5
Hitung mundur 4
Hitung mundur 3
Pemeriksaan menit 0
Pemeriksaan menit 4
Pemeriksaan menit 8
Pemeriksaan menit 12

Bentuk 1.upto(3) menaikkan nilai satu per satu, 5.downto(3) menurunkannya, sedangkan 0.step(12, 4) melompat dengan jarak empat hingga batas 12. Ketiganya menghasilkan Enumerator apabila blok tidak diberikan, tetapi bentuk dengan blok seperti di atas adalah penggunaan sehari-harinya. Kurung kurawal pada contoh adalah bentuk blok lain selain do ... end, yang lazim digunakan untuk badan satu baris.

each dan gaya iterasi Ruby#

Untuk koleksi seperti array, Ruby lebih sering menggunakan metode each daripada while dengan variabel indeks. Metode each menjalankan blok untuk setiap elemen dan menyampaikan elemen itu ke variabel blok, sehingga penulisan indeks dan batas perulangan tidak diperlukan. Contoh berikut membagi jadwal piket dengan mengambil anggota dari urutan terdepan satu per satu.

ruby jadwal-piket.rb
# Penugasan piket dengan each sebagai gaya iterasi Ruby.
anggota = ["Ali", "Budi", "Citra", "Dewi", "Eka", "Farhan"]
hari = ["Senin", "Selasa", "Rabu", "Kamis"]

hari.each do |nama_hari|
  petugas = anggota.shift
  puts "#{nama_hari}: #{petugas}"
end

puts "Sisa anggota tanpa jadwal: #{anggota.join(", ")}"
text Keluaran
Senin: Ali
Selasa: Budi
Rabu: Citra
Kamis: Dewi
Sisa anggota tanpa jadwal: Eka, Farhan

Metode shift mengambil elemen terdepan array sekaligus mengeluarkannya, sehingga baris keluaran terakhir menyisakan dua nama yang belum kebagian jadwal. Pola ini meniru perilaku antrean, yaitu yang datang lebih dulu dilayani lebih dulu. Variabel yang diterima blok hanya berlaku di dalam blok, sehingga tidak meninggalkan variabel sisa setelah perulangan berakhir.

Ruby juga menyediakan perulangan for ... in yang setara dengan each. Bentuk ini jarang digunakan dalam kode Ruby sehari-hari karena variabel iterasinya tetap tersedia setelah perulangan berakhir, berbeda dari variabel blok yang ikut hilang. Berikut bentuknya untuk perbandingan.

ruby for in sebagai alternatif yang jarang dipakai
for n in 1..3
  puts "Baris #{n}"
end
text Keluaran
Baris 1
Baris 2
Baris 3

Kesalahan umum#

Kesalahan pertama adalah perulangan while yang kondisinya tidak pernah berubah. Menghapus baris sisa -= 1 pada contoh di atas membuat sisa > 0 selalu benar, sehingga program mencetak baris yang sama tanpa akhir dan hanya berhenti ketika dihentikan paksa dari terminal. Perulangan berbasis kondisi selalu memerlukan satu pernyataan yang menggerakkan keadaan menuju kondisi berakhir, dan baris itu paling aman ditulis lebih dulu, sebelum isi badan.

Kesalahan kedua adalah salah hitung batas, yang paling sering muncul pada times. Menulis puts "Piket hari ke-#{nomor}" tanpa penjumlahan menghasilkan urutan yang dimulai dari nol, sedangkan menggunakan <= pada while dengan batas yang sama menambah satu iterasi ekstra. Kebiasaan yang berguna adalah memutuskan lebih dulu apakah kasusnya berbasis indeks dari nol atau berbasis hitungan manusia, lalu tetap konsisten pada satu konvensi hingga badan perulangan selesai ditulis.

Ringkasan#

  • while mengulang selama kondisi benar dan until mengulang sampai kondisi benar, keduanya menilai kondisi sebelum setiap iterasi.
  • loop mengulang blok tanpa syarat dan berakhir hanya melalui break, sedangkan next melompat ke iterasi berikutnya.
  • Iterator times, upto, downto, dan step mengulang dengan jumlah langkah pasti, dan indeks times dimulai dari nol.
  • each mengiterasi setiap elemen koleksi dan menjadi gaya perulangan yang paling khas Ruby, sedangkan for in tersedia tetapi jarang digunakan.

Referensi#