Bab 3 Struktur Kendali dan Pengulangan

//TODO: Di bab ini akan membahas fungsi if-else-then dan looping (for, while dan repeat)

3.1 Operator Logika

Ketika membahas struktur kendali pada suatu bahasa pemrograman pasti akan membahas tentang operator logika atau logical operator. Nilai dari logika akan selalu bernilai TRUE atau FALSE. Berikut ini tabel operator logika dan penjelasannya.

Tabel 3.1: Operator Logika
Operator Logika
& dan (AND)
| atau (OR)
! negasi (NOT)
== sama dengan (EQUAL)
!= tidak sama dengan (NOT EQUAL)
%in% ada diantara (IN)
> lebih besar dari (GREATER)
< lebih kecil dari (LESS)
>= lebih besar dari atau sama dengan (GREATER OR EQUAL)
<= lebih kecil dari atau sama dengan (LESS OR EQUAL)
&& dan (AND) (vector)
|| atau (OR) (vector)

Selanjutnya contoh nilai dari operator logika. Misalnya untuk p bernilai TRUE dan q bernilai TRUE, maka nilai untuk p & q (p dan q) adalah TRUE & TRUE yaitu TRUE.

Tabel 3.2: Contoh Hasil Operator Logika
p q p & q p | q !p p == q p != q
TRUE TRUE TRUE TRUE FALSE TRUE FALSE
TRUE FALSE FALSE TRUE FALSE FALSE TRUE
FALSE TRUE FALSE TRUE TRUE FALSE TRUE
FALSE FALSE FALSE FALSE TRUE TRUE FALSE

Operator lain yang juga sering digunakan adalah %in% (operator in). Operator ini digunakan untuk mengetahui apakah suatu nilai yang ada dalam sebuah vector. Misalnya contoh berikut ini.

2 %in% 1:5
## [1] TRUE

Program di atas artinya untuk mengetahui apakah nilai numerik 2 ada diantara vector numeric yang nilainya 1 sampai dengan 5. Karena nilai 2 ada diantara 1 sampai dengan 5 maka nilai dari program di atas adalah TRUE. Begitu juga jika nilai yang ingin diketahui adalah character. Seperti contoh berikut ini.

"a" %in% c("ab", "a", "b", "ac")
## [1] TRUE

Program di atas mencari nilai character "a" yang sama persis diantara nilai vector c("ab", "a", "b", "ac"). Maka yang dianggap sama adalah elemen kedua dari vector tersebut. Karena "a" tidak sama dengan "ab" atau "ac".

Berikutnya adalah operator perbandingan. Operator-operator ini digunakan untuk membandingkan nilai numerik.

1 > 2 # 1 tidak lebih besar dari 2
## [1] FALSE
2 > 1 # 2 lebih besar dari 1
## [1] TRUE

Ketika sebuah nilai numerik dibandingkan dengan sebuah vector numerik yang mempunyai length() lebih dari 1, maka nilai numerik di sebelah kiri operator akan dievaluasi terhadap masing-masing nilai pada vector tersebut. Misalnya contoh berikut ini.

2 > 1:5
## [1]  TRUE FALSE FALSE FALSE FALSE

Nilai 2 disebelah kiri operator dievaluasi terhadap masing-masing elemen pada vector sebelah kanan. Maka dari itu karena 2 lebih besar dari 1 hasilnya adalah TRUE. Selanjutnya karena 2 tidak lebih besar dari 2, 3, 4, dan 5 maka sisanya bernilai FALSE. Perhatikan contoh berikut ini.

2 >= 1:5
## [1]  TRUE  TRUE FALSE FALSE FALSE
2 < 1:5
## [1] FALSE FALSE  TRUE  TRUE  TRUE
2 <= 1:5
## [1] FALSE  TRUE  TRUE  TRUE  TRUE

Operator logika terakhir yang akan kita bahas adalah operator && dan ||. Operator && adalah operator AND dan || adalah OR. Mungkin Anda bertanya, “Apa perbedaannya dengan operator & dan |?” Ingat bahwa operator & dan | mengevaluasi masing-masing nilai jika yang dibandingkan adlaah vector. Misalnya c(TRUE, FALSE) && c(FALSE, TRUE) akan menghasilkan dua nilai FALSE karena masing-masing elemen dievaluasi terhadap pasangannya (elementwise). Pada operator && dan || yang dievaluasi hanya elemen pertama pada setiap vector. Untuk lebih jelasnya perhatikan contoh berikut ini.

p <- c(TRUE, TRUE, FALSE, FALSE)
p
## [1]  TRUE  TRUE FALSE FALSE
q <- c(TRUE, FALSE, TRUE, FALSE)
q
## [1]  TRUE FALSE  TRUE FALSE

Dari program di atas kita usdah mempunyai dua buah vector, p dan q. Dua buah vector ini masing-masing berisi empat elemen berupa nilai logical (TRUE atau FALSE). Jika kita gunakan operator & pada p & q maka hasilnya adalah evaluasi dari masing-masing elemen sehingga hasilnya akan ada empat elemen.

p & q
## [1]  TRUE FALSE FALSE FALSE

Berbeda halnya ketika kita gunakan operator &&. Ketika kita gunakan operator && pada p && q maka yang akan dievaluasi adalah elemen pertama dari p dan q. Elemen pertama dari p adalah TRUE dan elemen pertama dari q adalah TRUE juga. Maka hasil dari p && q adalah TRUE & TRUE yaitu TRUE. Perhatikan bahwa karena hanya elemen pertama dari masing-masing vector yang dievaluasi sehingga hasilnya adalah sebuah vector dengan satu elemen.

p && q
## [1] TRUE

Contoh lain agar Anda lebih paham mengenai konsep operator && ini.

c(TRUE, FALSE) && c(FALSE, TRUE)
## [1] FALSE
c(FALSE, FALSE) && c(FALSE, TRUE)
## [1] FALSE
c(TRUE, TRUE) && c(FALSE, TRUE)
## [1] FALSE
c(TRUE, FALSE) && TRUE
## [1] TRUE
FALSE && c(FALSE, TRUE)
## [1] FALSE

Konsep yang serupa juga berlaku untuk operator ||.

p || q
## [1] TRUE
c(TRUE, FALSE) || c(FALSE, TRUE)
## [1] TRUE
c(FALSE, FALSE) || c(FALSE, TRUE)
## [1] FALSE
c(TRUE, TRUE) || c(FALSE, TRUE)
## [1] TRUE
c(TRUE, FALSE) || TRUE
## [1] TRUE
FALSE || c(FALSE, TRUE)
## [1] FALSE

3.2 Fungsi if() dan ifelse()

Struktur kendali pada bahasa pemrograman R yang umum digunakan adalah fugsi if(). Argumen yang dibutuhkan pada fungsi if() adalah sebuah vector logical tunggal bernilai TRUE atau FALSE. Untuk mendapatkan nilai logical ini kita gunakan operator logika yang sudah kita bahas sebelumnya.

2 < 3
## [1] TRUE

Bentuk umum dari perintah menggunakan if() adalah sebagai berikut.

if(kondisi) ekspresi

Berikut ini contoh program untuk menjalankan sebuah perintah menuliskan sebuah teks ketika kondisi bernilai benar.

if(2 < 3) print("Kondisi tersebut benar")
## [1] "Kondisi tersebut benar"

Jika ada perintah yang akan dijalankan ketika masing-masing kondisi bernilai benar atau salah, maka bentuk umumnya adalah sebagai berikut. Ekspresi atau perintah yang ada pada kondisi else{} akan dijalankan ketika kondisi pada if() bernilai salah.

if(kondisi){
  ekspresi jika kondisi benar
} else {
  ekspresi jika kondisi salah
}

Perhatikan contoh berikut ini.

if(2 > 3){
  # Jika kondisi benar
  print("Kondisi tersebut benar")
} else {
  # Jika kondisi salah
  print("Kondisi tersebut salah")
}
## [1] "Kondisi tersebut salah"

Di atas kita sudah membahas contoh sederhana penggunaan if() dengan hanya satu kondisi. Selanjutnya bagaimana jika nilai yang ada pada kondisi berisi lebih dari satu nilai benar atau salah? Kita ingat kembali bahwa sebelumnya kita telah membuat sebuah objek bernama p yang merupakan sebuah vector berisi nilai logical, yaitu TRUE, TRUE, FALSE, FALSE. Ketika kondisi pada fungsi if() mempunyai lebih dari satu nilai maka hal yang pertama akan muncul adalah warning seperti berikut ini.

p <- c(TRUE, TRUE, FALSE, FALSE)
if(p){
  print(p)
}
## Warning in if (p) {: the condition has length > 1 and only the first element
## will be used
## [1]  TRUE  TRUE FALSE FALSE

Dari warning di atas dapat kita ketahui bahwa fungsi if() hanya menggunakan elemen pertama dari vector p sebagai kondisi yang dievaluasi. Karena nilai pertama dari vector p adalah TRUE maka perinath print(p) dijalankan, yaitu mencetak semua nilai pada vector p. Jika kita buat negasi dari p dengan !p, maka elemen pertamanya menjadi FALSE sehingga perintah print(p) tidak akan dijalankan. Namun tetap ada warning yang muncul karena kondisi yang diberikan memiliki lebih dari satu nilai logical.

if(!p){
  print(p)
}
## Warning in if (!p) {: the condition has length > 1 and only the first element
## will be used

Untuk dapat melakukan evaluasi pada masing-masing nilai logical dari vector p, kita dapat gunakan fungsi ifelse(). Bentuk umumnya sedikit berbeda dibandingkan dengan fungsi if() yang sudah kita bahas.

ifelse(kondisi, true, false)

Fungsi ifelse() akan mengevaluasi setiap nilai yang ada pada kondisi dan menjalankan perintah yang bersesuaian. Misalnya, karena nilai elemen pertama dan kedua pada vector p adalah TRUE maka perintah pada argumen true akan dijalankan. Namun ketika elemen ketiga dan keempat bernilai FALSE maka perintah pada argumen false akan dijalankan. Output dari fungsi ifelse() adalah berupa vector.

ifelse(p, "benar", "salah")
## [1] "benar" "benar" "salah" "salah"
ifelse(!p, "benar", "salah")
## [1] "salah" "salah" "benar" "benar"

3.3 Fungsi switch()

Selain fungsi if() yang dapat digunakan sebagai struktur kendali, di R juga terdapat fungsi switch(). Cara kerja fungsi switch() secara umum mirip seperti fungsi if(), yaitu menjalankan perintah yang sesuai dengan kondisi yang ada. Fungsi ini secara umum digunakan untuk menjalankan suatu perintah berdasarkan pilihan yang sudah ditentukan dan dibuat di dalam sebuah function. Sebagai contoh, di bawah ini kita akan menggunakan fungsi switch() untuk menghitung nilai mean, median atau trimmed (rataan terpotong). Argumen yang kita gunakan pada contoh ini kita namakan type. Cara kerjanya adalah sebagai berikut. Jika type yang digunakan adalah "mean" maka fungsi yang akan dijalankan adalah fungsi mean dari input yang diberikan. Jika type = "median" maka fungsi yang akan digunakan adalah median dari input yang diberikan, dan seterusnya.

x <- 1:12
type <- 'mean'
switch(type,
       mean = mean(x),
       median = median(x),
       trimmed = mean(x, trim = .1))
## [1] 6.5

Misalnya kita buat sebuah fungsi bernama center untuk memudahkan penggunaan perintah di atas.

center <- function(x, type) {
  switch(type,
         mean = mean(x),
         median = median(x),
         trimmed = mean(x, trim = .1))
}

Ketika kita ingin menghitung rata-rata dari vector x kita cukup menuliskannya seperti berikut ini.

center(x, 'mean')
## [1] 6.5

Begitu juga ketika kita ingin menghitung median atau rata-rata terpangkas (trimmed), maka kita cukup mengganti 'mean' dengan pilihan yang sesuai.

center(x, 'median')
## [1] 6.5
center(x, 'trimmed')
## [1] 6.5

3.4 Looping for()

Ketika membicarakan tentang melakukan proses looping dalam sebuah baasa pemrograman, pastinya yang akan dibahas adalah looping for(). Begitu juga di bahasa pemrograman R. Bentuk umum dari looping for() adalah sebagai berikut. Looping for() umumnya digunakan ketika kita mengetahui berapa kali iterasi yang akan dilakukan.

for(indeks in vector) ekspresi
# atau
for(indeks in vector){
  ekspresi1
  ekspresi2
  ...
}

Fungsi for() membutuhkan 2 argumen utama, yaitu sebuah objek yang akan menjadi indeks dan sebuah vector atau list. Objek indeks yang nantinya akan bernilai sesuai dengan urutan yang ada pada vector tersebut. Kemudian ekspresi adalah perintah atau program yang akan dijalankan. Perhatikan contoh berikut ini.

for(i in 1:5){
  msg <- paste0("looping for ke-", i)
  message(msg)
}
## looping for ke-1
## looping for ke-2
## looping for ke-3
## looping for ke-4
## looping for ke-5

Argumen i in 1:5 pada looping for() di atas berarti looping ini akan menjalankan perintah dengan indeks i bernilai 1 sampai dengan 5 pada setiap iterasinya. Atau dengan kata lain kita memerintahkan R untuk melakukan iterasi sebanyak 5 kali. Kemudian karena indeks i digunakan pada fungsi paste0(), maka nilai i akan berubah sesuai dengan nilai i pada iterasi tersebut.

Namun saat ini banyak pengguna R mulai banyak yang enggan menggunakan for() untuk melakukan iterasi. Alasannya adalah karena for() merupakan sebuah perintah untuk melakukan iterasi yang performanya cukup lambat. Oleh karena itu, saat ini banyak yang lebih menyarankan untuk menggunakan fungsi dari family apply (apply, sapply, tapply, dan lain-lain). Atau ada juga yang lebih senang menggunakan fungsi dari package seperti map(), map_dfr() dan lain-lain dari package {purrr}. Alasanya adalah karena fungsi-fungsi tersebut dibuat dari bahasa pemrograman C++ sehingga memiliki performa yang lebih cepat dibandingkan dengan for().

3.5 Looping while()

Berbeda dengan fungsi for() yang digunakan ketika kita sudah mengetahui banayaknya iterasi yang akan dijalankan, baik itu secara eksplisit ataupun secara pemrograman, while() digunakan ketika kita tidak mengetahui banyaknya iterasi yang akan dijalankan namun mengetahui kondisi logical yang menjadi syarat program tersebut tetap berjalan. Bentuk umum dari looping while() ini adalah sebagai berikut.

while(kondisi) {
  ekspresi
  ...
}

Argumen kondisi adalah sebuah nilai logical (TRUE atau FALSE). Ekspresi atau perintah yang ada di dalam while() akan terus dijalankan selama kondisi bernilai TRUE. Satu hal penting yang harus diingat ketika menggunakan while() adalah kita harus bisa memastikan bahwa argumen kondisi suatu saat akan bernilai FALSE agar iterasinya berhenti.

i <- 0
while(i < 5){
  print(i)
  i <- i + 1
}
## [1] 0
## [1] 1
## [1] 2
## [1] 3
## [1] 4
i <- 0
while(i < 5){
  i <- i + 1
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

3.6 Looping repeat

Fungsi terakhir untuk looping yang akan dibahas pada buku ini adalah menggunakan fungsi repeat untuk looping. Looping repeat ini lebih mirip dengan while() karena syarat berhenti iterasinya berdasarkan suatu kondisi logical menggunakan if(kondisi) break.

repeat {
  ekspresi
  ...
  if(kondisi) break
}

Perintah berikut ini adalah perintah untuk menjalankan hal yang sama dengan perintah ketika kita menggunakan fungsi while().

i <- 0
repeat {
  if(i>4) {
    break # repeat selesai
  }
  i <- i + 1
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5