Perulangan dan Uji Kondisi (4)

.

Uji kondisi “switch”

Berbeda dengan perintah if yang menguji kondisi satu per satu, perintah switch bisa menguji beberapa nilai sekaligus serta bisa menguji nilai dengan pola tertentu. Dan lagi, uji kondisi if bekerja dengan nilai logika, sementara uji kondisi switch bekerja dengan nilainya langsung. Berikut cara penulisan perintah switch:

switch value {
case value_1:
// kelompok perintah A
case value_2,
value_3:
// kelompok perintah B
default:
// kelompok perintah C
}

value adalah nilai yang akan diuji, case memetakan setiap nilai yang mungkin terjadi, dan default untuk nilai lainnya. Dalam hal ini, default bekerja seperti else dalam perintah if, yang bekerja ketika semua uji kondisi tidak lolos. Sebuah case bisa memetakan beberapa nilai sekaligus dengan menggunakan tanda , (koma) sebagai pemisah seperti penulisan value_2 dan value_3 di atas.

Perlu diperhatikan bahwa kelompok perintah di dalam case atau default tidak perlu diapit tanda {} seperti biasanya karena telah diapit oleh sesama case atau penanda kelompok switch tersebut. Ini kekhususan perintah switch.

Contoh:

// buat variabel teks
var aCharacter = "a"
// tentukan jenis huruf
switch aCharacter {
case "a", "i", "u", "e", "o":
print(aCharacter,"adalah huruf vokal")
case "b", "c", "d", "f", "g", "h", "j",
"k", "l", "m", "n", "p", "q", "r",
"s", "t", "v", "w", "x", "y", "z":
print(aCharacter,"adalah huruf konsonan")
default:
print(aCharacter,"adalah huruf lainnya")
}

Seperti yang disebutkan sebelumnya, uji kondisi dengan switch bisa untuk menguji pola nilai. Perintah case memiliki beberapa keistimewaan untuk tujuan tersebut yang tidak tersedia pada uji kondisi dengan if. Yang pertama adalah case mendukung nilai rentang. Contoh:

// buat variabel untuk nilai ujian
var score = 87 // nilai dalam angka
// menentukan nilai huruf dari rentang angka
switch score {
case 10 ... 40: print("E")
case 41 ... 55: print("D")
case 56 ... 70: print("C")
case 71 ... 80: print("B")
case 81 ... 100: print("A")
default: print("F")
}

Contoh di atas akan mencetak “A” karena penyimpan score bernilai 87 berada di rentang 81 hingga 100. Keistimewaan kedua, case mempunyai perintah khusus yaitu fallthrough yang gunanya untuk masuk ke kelompok case selanjutnya tanpa harus melewati uji kondisi pada case yang dimasuki tersebut. Contoh:

// buat variabel untuk nilai ujian
var score = 21 // nilai dalam angka
// menentukan nilai huruf dari rentang angka
switch score {
case 10 ... 40: print("E"); fallthrough
case 41 ... 55: print("D"); fallthrough
case 56 ... 70: print("C")
case 71 ... 80: print("B")
case 81 ... 100: print("A")
default: print("F")
}

Contoh di atas tidak hanya mencetak “E”, tapi juga mencetak “D” dan “C”, walau pun nilai score tidak berada dalam rentang 41 hingga 70. Ini karena adanya perintah fallthrough pada 2 (dua) case di awal. Urutan proses program di atas adalah sebagai berikut:

  • Membuat variabel score bernilai 21 (bertipe bilangan bulat).
  • Melakukan uji kondisi dengan switch pada penyimpan score.
  • Jika rentang nilai score berada dalam rentang 10 hingga 40, cetak “E”.
  • Karena ada perintah fallthrough maka program langsung masuk pada case selanjutnya, tanpa melakukan uji kondisi.
  • Cetak “D”.
  • Karena ada perintah fallthrough maka program langsung masuk pada case selanjutnya, tanpa melakukan uji kondisi.
  • Cetak “C”.
  • Keluar dari kelompok perintah switch.

Karena perilaku yang demikian, perintah fallthrough dalam case ini harus digunakan dengan hati-hati sebab agak bertentangan dengan tujuan uji kondisi. Efek buruk lain dari perilaku tersebut, segala perintah setelah fallthrough (dalam case terkait) diabaikan karena fallthrough akan melompat langsung ke case selanjutnya (atau default). Oleh karena itu, sebaiknya penggunaan perintah fallthrough dihindari kecuali memang algoritma program mengharuskan demikian dan tak ada algoritma lain yang lebih baik.

Diagram alur uji kondisi dengan “switch-case” yang berisi “fallthrough”. Sumber: sendiri.

Keistimewaan yang ketiga, yang terpenting, adalah adanya perintah pelengkap (clause) where dalam perintah case. Pelengkap where ini berfungsi untuk uji kondisi tambahan atas nilai yang diberikan. Ini mirip seperti fungsi perintah if namun bekerja dalam perintah case. Contoh:

// buat variabel bilangan bulat
var v = 4
switch v {
// uji apakah v habis dibagi 3 dan 5
case v where (v % 3 == 0) && (v % 5 == 0):
print("FizzBuzz")
// uji apakah v habis dibagi 3
case v where v % 3 == 0:
print("Fizz")
// uji apakah v habis dibagi 5
case v where v % 5 == 0:
print("Buzz")
// v tak habis dibagi 3 atau 5
default:
print("No FizzBuzz")
}

Cara membaca kode program di atas adalah sebagai berikut:

  • Membuat variabel v bernilai 4 (tipe bilangan bulat).
  • Uji kondisi variabel v dengan perintah switch.
  • Uji nilai v dengan where apakah habis dibagi 3 dan habis dibagi 5. Jika benar, cetak “FizzBuzz”.
  • Uji nilai v dengan whereapakah habis dibagi 3. Jika benar, cetak “Fizz”.
  • Uji nilai v dengan whereapakah habis dibagi 5. Jika benar, cetak “Buzz”.
  • Jika tak lolos semua ujian (default), cetak “No FizzBuzz”.

Karena v diberi nilai 4, yang artinya tak bisa dibagi baik oleh 3 maupun 5, maka program akan mencetak “No FizzBuzz”.

Diagram alur uji kondisi dengan “switch-case” yang berisi “where”. Sumber: sendiri.

Pelengkap where ini sangat bermanfaat untuk pemetaan pola terhadap nilai yang diuji, terutama jika melibatkan tipe data kelompok seperti deret atau kamus. Walaupun sebenarnya bisa juga dilakukan dengan perintah if, tapi pemetaan pola dengan perintah switch lebih mudah ditulis dan dibaca. Ini keunggulan utama dari perintah uji kondisi switch dalam Swift.

Kendali perulangan

Dalam kondisi-kondisi tertentu, sebuah perulangan perlu dihentikan untuk atau dilangkahi agar alur program menjadi lebih efektif dan efisien sehingga lebih hemat sumber daya komputer. Apalagi jika perulangan memungkinkan untuk berulang tanpa henti (never ending loop). Ada 2 (dua) perintah untuk kendali perulangan di Swift, yaitu continue dan break.

Melangkahi perulangan

Dalam perulangan biasanya ada proses yang perlu dilakukan. Tak jarang proses tersebut cukup panjang atau rumit. Namun, kadang ada beberapa kondisi (atau nilai) tertentu yang tak perlu melalui proses tersebut. Program bisa melangkahi kondisi demikian, yaitu dengan mengabaikan urutan proses dalam perulangan tersebut dan melanjutkan perulangan untuk kondisi yang lain atau selanjutnya. Itulah fungsi dari perintah continue.

Contoh:

// buat variabel teks
var s = "Gajah H-nya ada dimana?"
// ulang tiap huruf dalam teks
for ch in s.characters {
// uji huruf, jika bukan "H" langsung lompat ke huruf selanjutnya
if ch != "H" { continue }
// cetak huruf
print(ch)
}

Pada contoh program di atas, sebuah teks berisi 23 (dua puluh tiga) huruf — termasuk tanda spasi. Kita mencari huruf “H” dalam teks tersebut. Jika ditemukan, lakukan suatu proses, yaitu mencetak huruf tersebut. Jika tidak ditemukan, lompati proses dan langsung ke huruf selanjutnya. Dengan demikian, program tak perlu melakuran proses jika memang tak diperlukan.

Menghentikan perulangan

Dalam kasus tertentu, kita tak bisa tentukan di awal kapan perulangan harus berhenti. Keputusan penghentian perulangan baru diketahui melalui proses yang ada di dalam perulangan itu sendiri. Atau dalam kasus lain, ada kondisi tertentu yang bisa menghentikan perulangan karena perulangan selanjutnya sudah tidak dibutuhkan lagi. Bagaimana menghentikan sebuah perulangan yang sedang berjalan? Itulah fungsi dari perintah break.

Contoh:

// buat variabel teks
var s = "Gajah H-nya ada dimana?"
// ulang tiap huruf dalam teks
for ch in s.characters {
// cetak huruf
print(ch)
// uji huruf, jika "H" hentikan perulangan
if ch == "H" {
print("H-nya ditemukan!")
break
}
}

Pada program contoh di atas, tujuannya adalah untuk mencari huruf “H” dalam sebuah teks. Caranya dengan melakukan perulangan menguji setiap huruf sepanjang teks dan mencetak setiap hurufnya. Jika bertemu dengan huruf “H” maka perulangan tak perlu lagi dilanjutkan. Cukup cetak petunjuk bahwa huruf “H” sudah ditemukan dan hentikan program dengan perintah break. Dengan begitu, program tak perlu melakukan perulangan terhadap sisa huruf lagi.

Dua contoh program di atas bisa kita gabungkan untuk membuat program pencarian huruf lebih efisien. Algoritmanya menjadi… Jika huruf yang dicari belum ditemukan, tak perlu mencetak huruf. Jika huruf yang dicari telah ditemukan, cetak pemberitahuan. Berikut hasilnya:

// buat variabel teks
var s = "Gajah H-nya ada dimana?"
// ulang tiap huruf dalam teks
for ch in s.characters {
// uji huruf, jika bukan "H" lanjutkan perulangan
if ch != "H" { continue }
// cetak huruf
print(ch)
// uji huruf, jika "H" hentikan perulangan
if ch == "H" {
print("H-nya ditemukan!")
break
}
}
Diagram alur dampak perintah “continue” dan “break” dalam perulangan. Sumber: sendiri.

Uji kondisi nilai tak-tentu

Pada bahasan nilai tak-tentu (optionals) sebelumnya, kita tahu bahwa bekerja dengan nilai tak-tentu itu merepotkan. Jika kita ingin bekerja dengan nilai tersebut, selain kita harus memastikan nilainya sesuai dengan yang kita inginkan, sebelumnya kita juga harus memastikan bahwa nilainya tidak nil, atau program kita akan gagal bekerja. Saat bekerja dengan nilai tak tentu, kita akan banyak menemui kode program seperti berikut ini:

// buat variabel bilangan tak-tentu
var i: Int? = Int("123")
// uji nilai i terhadap nil
if i != nil {
// bukan nil, lakukan proses selanjutnya
let j = i! // paksa nilai tak-tentu ke nilai tetap lokal
print(j) // cetak nilai j (nilai tetap)
} else {
// nil, tampilkan pesan kesalahan
print("Nilai kosong, tak bisa diproses.")
}

Contoh di atas sederhana, jika nilai i bukan nil maka kita hanya ingin mencetak nilai i. Dalam aplikasi yang sebenarnya, bisa jadi prosesnya cukup panjang dan rumit. Dan kita harus ingat untuk memaksa nilai i menjadi nilai tetap dengan tanda !. Itu sebabnya nilai i yang tak-tentu disimpan ke penyimpan baru (dalam lingkup kelompok perintah if yang terkait) bernama j yang bertipe data tetap untuk menghindari resiko kita lupa memasang tanda ! jika langsung menggunakan i. Kode yang cukup merepotkan bukan?

Karena itu, Swift memberikan kita solusi yang lebih mudah untuk bekerja dengan pengujian nilai tak-tentu. Istilahnya adalah pengikatan nilai tak-tentu atau disebut optional binding. Kode contoh program di atas bisa ditulis dengan lebih sederhana menggunakan pengikatan nilai tak-tentu seperti berikut ini:

// buat variabel bilangan tak-tentu
var i: Int? = Int("123")
// uji nilainya terhadap nil
if let j = i {
print(j) // cetak nilai j (nilai tetap)
} else {
// nil, tampilkan pesan kesalahan
print("Nilai kosong, tak bisa diproses.")
}

let bisa diganti var, tergantung kebutuhan apakah kita ingin mengubah nilai pengikatan, atau tidak. Kebanyakan pemrogram Swift menyamakan nama penyimpan pengikat dengan nama penyimpan aslinya, tujuannya untuk memudahkan pemahaman alur program. Jadi, contoh program di atas bisa juga ditulis seperti berikut:

// buat variabel bilangan tak-tentu
var i: Int? = Int("123")
// uji nilainya terhadap nil
if var i = i {
i = i*2 // ubah nilai i (lokal nilai tetap)
print(i) // cetak nilai i (lokal nilai tetap)
} else {
// nil, tampilkan pesan kesalahan
print("Nilai kosong, tak bisa diproses.")
}

Namun perlu diingat bahwa penyimpan i yang berada dalam lingkup if (bertipe nilai tetap) itu berbeda dengan penyimpan i yang berada di luar lingkup if (bertipe nilai tak-tentu). Mengubah nilai i yang di dalam tidak mengubah nilai i yang di luar. Setiap penyimpan mengikuti lingkup tempat dimana ia berada.

Swift mengijinkan operasi pengikatan untuk beberapa penyimpan nilai tak-tentu sekaligus. Cukup gunakan tanda , (koma) sebagai pemisah antar operasi. Pemisah koma dalam operasi pengikatan nilai tak-tentu bersifat seperti operator && (operasi logika dan [and]) sehingga jika ada salah satu saja proses pengikatan nilai tak-tentu yang gagal (ada nilai nil) maka uji kondisi menjadi gagal.

Selanjutnya, kita akan membahas tentang Fungsi.