For loop dasar
for loop di R menjalankan sebuah blok kode sekali untuk setiap elemen vector atau list. Variabel loop mengambil setiap nilai secara bergiliran:
Tiga elemen, tiga putaran. Tidak ada penghitung yang perlu disiapkan dan tidak ada kondisi yang perlu dijaga: for (fruit in fruits) dibaca sebagai "untuk setiap fruit di dalam fruits", dan persis itulah yang dilakukannya. Bentuk yang sama bisa menelusuri elemen-elemen list, deret angka (for (i in 1:10)), atau nama-nama apa pun lewat names().
Mencetak di dalam loop butuh print() atau cat()
Di console, mengetik x akan mencetak nilainya. Di dalam isi loop, tidak: pencetakan otomatis hanya terjadi di tingkat teratas, dan ekspresi biasa di dalam loop dievaluasi lalu dibuang:
Jadi saat sebuah loop "tidak melakukan apa-apa", inilah hal pertama yang perlu diperiksa. Pakai print() untuk melihat sekilas nilai apa pun, atau cat() saat kamu menyusun sendiri satu baris output (ingat "\n", karena cat() tidak menambahkannya).
Perulangan pada indeks dengan seq_along()
Kadang kamu butuh posisi sekaligus nilainya, misalnya untuk menulis ke vector lain pada indeks yang sama, atau untuk mencetak daftar bernomor. Lakukan perulangan pada indeks dengan seq_along():
Kamu akan melihat for (i in 1:length(prices)) di kode lama, dan bentuk itu menyimpan bug sungguhan. Saat vector-nya kosong, length() bernilai 0, dan 1:0 tidak berarti "tanpa iterasi"; titik dua justru menghitung mundur:
Loop pada 1:length(empty) berjalan dua kali dan mengindeks elemen yang tidak ada (empty[1] bernilai NA, dan penugasan membuat entri hantu). seq_along() mengembalikan deret kosong untuk vector kosong, sehingga isi loop tidak pernah dijalankan. Jadikan seq_along() kebiasaan; saudaranya seq_len(n) melakukan tugas yang sama saat yang kamu punya adalah jumlah, bukan vector.
Mengumpulkan hasil: alokasikan di awal, jangan ditumbuhkan
Naluri pertama yang wajar untuk mengumpulkan hasil terlihat seperti ini:
squares <- c()
for (i in 1:10000) {
squares <- c(squares, i^2) # copies the ENTIRE vector every pass
}
Cara ini berhasil, tapi setiap c(squares, ...) mengalokasikan vector yang benar-benar baru dan menyalin semua elemen lama ke dalamnya. Pada akhirnya kamu sudah menyalin sekitar 50 juta angka untuk menghasilkan 10.000. Anti-pola vector yang terus tumbuh inilah alasan terbesar orang menyebut loop R lambat.
Solusinya: buat hasilnya dengan ukuran penuh lebih dulu, lalu isi berdasarkan indeks:
Untuk hasil yang bukan angka, gagasan yang sama berlaku dengan character(n), logical(n), atau vector("list", n) untuk list berisi apa saja. Loop yang dialokasikan di awal berjalan sangat cepat.
next dan break
Dua kata kunci mengarahkan loop dari dalam isinya: next meninggalkan putaran saat ini dan melompat ke elemen berikutnya; break keluar dari loop sepenuhnya.
Ini mencetak 2 4 6 8: nilai ganjil dilewati oleh next, dan saat 10 tiba, break mengakhiri loop sebelum mencetak. Pakai next untuk menyaring kasus sejak awal (isi utamanya jadi tidak perlu diindentasi), dan break saat loop sudah menemukan apa yang dicarinya dan tidak punya alasan untuk lanjut.
Loop bersarang
Isi loop bisa berisi loop lain. Loop dalam berjalan sampai selesai untuk setiap putaran loop luar; contoh klasiknya adalah tabel perkalian:
Untuk setiap baris i, loop dalam menelusuri semua kolom j, dan baris baru untuk baris itu dicetak setelah loop dalam selesai. Loop bersarang dua tingkat masih wajar; pada tiga tingkat atau lebih, isinya biasanya minta dijadikan fungsi, atau seluruh perhitungannya minta dijadikan outer() atau operasi matrix.
Loop bersarang juga mencakup perulangan pada list berisi vector: loop luar pada list, loop dalam (atau lebih baik, pemanggilan tervektorisasi) pada setiap elemen:
Perhatikan bahwa ternyata tidak ada loop dalam: mean() menangani seluruh vector dalam satu pemanggilan. Pengamatan itu berlaku lebih luas, dan itu membawa kita ke bagian yang jujur.
Kapan tidak perlu loop
R adalah bahasa tervektorisasi: operasi dasarnya sudah bekerja pada seluruh vector sekaligus. Loop yang mengubah setiap elemen satu per satu sering kali hanyalah cara yang lebih panjang untuk menulis satu baris:
Utamakan bentuk tervektorisasi setiap kali tersedia: lebih pendek, lebih sulit salah, dan lebih cepat. Untuk menerapkan sebuah fungsi pada setiap elemen list, keluarga apply (sapply, lapply, vapply) memainkan peran yang sama.
Tapi jangan menelan mentah-mentah lalu menyimpulkan "loop itu buruk". Loop adalah alat yang tepat saat setiap iterasi bergantung pada iterasi sebelumnya (state yang berjalan, simulasi), saat kamu melakukan efek samping seperti menulis file, atau sekadar saat loop adalah versi yang langsung dipahami olehmu dan pembacamu. Loop yang jelas lebih baik daripada satu baris cerdik yang tidak bisa dipahami siapa pun.
Yang kamu bawa pulang
for (x in v) { ... }menjalankan isinya sekali per elemen, tanpa repot mengurus penghitung.- Di dalam loop, cetak secara eksplisit dengan
print()ataucat(); ekspresi biasa dibuang. - Lakukan perulangan pada posisi dengan
seq_along(v), jangan pernah1:length(v), karena bentuk kedua berjalan dua kali pada vector kosong. - Alokasikan hasil di awal dengan
numeric(n)/vector("list", n)lalu isi berdasarkan indeks; menumbuhkan denganc()menyalin semuanya di setiap putaran. nextmelewati satu putaran,breakkeluar; utamakan operasi tervektorisasi saat tersedia, tapi jangan takut pada loop yang mudah dibaca.
Berikutnya: loop yang berjalan sampai sesuatu terjadi, bukan sekali per elemen, yaitu while dan repeat.
Pertanyaan yang sering diajukan
Bagaimana cara menulis for loop di R?
for (x in v) { ... }: variabel loop x mengambil setiap elemen vector (atau list) v secara bergiliran, dan isi loop dijalankan sekali untuk setiap elemen. Untuk melakukan perulangan pada posisi alih-alih nilai, pakai for (i in seq_along(v)) dan akses dengan v[i].
Kenapa memakai seq_along alih-alih 1:length(v) di R?
Saat v kosong, length(v) bernilai 0, sehingga 1:length(v) menjadi 1:0, yaitu vector dua elemen c(1, 0), dan isi loop dijalankan dua kali terhadap elemen yang tidak ada. seq_along(v) mengembalikan deret kosong untuk vector kosong, sehingga loop dengan benar dijalankan nol kali.
Kenapa for loop-ku di R tidak mencetak apa pun?
Pencetakan otomatis R hanya terjadi untuk ekspresi yang diketik di tingkat teratas console. Di dalam isi loop, ekspresi biasa seperti x dievaluasi lalu dibuang. Bungkus dengan print(x), atau pakai cat(...) saat kamu ingin memformat output-nya sendiri.
Apakah for loop lambat di R?
Loop-nya sendiri baik-baik saja; yang lambat adalah menumbuhkan vector di dalamnya dengan result <- c(result, ...), yang menyalin seluruh vector di setiap putaran. Alokasikan di awal dengan numeric(n) atau vector("list", n) lalu isi berdasarkan indeks, maka loop berjalan dengan sangat baik. Meski begitu, saat operasi tervektorisasi atau pemanggilan keluarga apply mengungkapkan gagasan yang sama, biasanya cara itu lebih cepat sekaligus lebih jelas.