BelajarVBA 010 - Perulangan 3 : FOR EACH dan keluar dari loop

Coretan Mr. Kid

Bermewah-mewahan dan tidak memerangi kebodohan diri akan membuat seseorang menjadi pecinta dunia dan melupakan bahwa kelak dia akan mempertanggungjawabkan segala perbuatannya

Perulangan (loop) berupa blok FOR ... NEXT dan DO ... LOOP telah dibahas pada episode sebelumnya. Pada umumnya, proses loop yang telah dibahas tersebut digunakan untuk melakukan loop terhadap suatu nilai dari suatu kondisi awal sampai kondisi akhir yang berupa nilai numerik. Penggunaan blok loop seperti FOR ... NEXT atau DO ... LOOP terhadap suatu array adalah dengan melakukan loop terhadap indeks elemen array. Sedangkan loop pada suatu object collection dilakukan terhadap indeks koleksinya.

Pembahasan kali ini adalah tentang blok FOR EACH yang dapat digunakan untuk melakukan loop terhadap setiap item arrayatau setiap item object collection. Misalnya melakukan loop terhadap setiap range pada suatu kumpulan range tertentu atau melakukan loop terhadap setiap worksheet yang ada di dalam workbook. Selain itu, akan dibahas pula tentang statement dan penyusunan baris kode agar proses loop berhenti ketika memang dikehendaki untuk berhenti pada saat nilai loop tersebut.



Bentuk dasar FOR EACH

Perulangan yang menggunakan statement FOR EACH akan melakukan perulangan dengan mengambil setiap elemen suatu grup data. Grup data bisa berupa array ataupun object collection. Jadi pada perulangan ini, nilai loop yang diproses adalah elemen suatu grup itu sendiri. Jika grup data berupa object collection, maka nilai loop adalah setiap item object dari object colletion tersebut.

Syntax :
   FOR EACH var_item IN grup_data
      'baris kode yang di-loop untuk setiap var_item
   NEXT var_item


Hal yang perlu diperhatikan :
  • var_item ber-datatype Variant jika grup_data adalah suatu array
  • var_item ber-datatype Variant, Object atau nama class object dari item dalam grup data jika grup_data adalah suatu object collection
  • minimal ada sebuah elemen atau item didalam grup_data
Contoh 1 :
Menampilkan nilai setiap kode dari sebuah daftar kode yang berisi nilai-nilai kode 10,15, dan 20. Pada kasus ini, dapat diketahui bahwa ada sebuah daftar kode yang berisi 3 buah nilai kode, yaitu 10,15, dan 20. Daftar ini berupa array. Proses loop dilakukan untuk mengambil setiap nilai kode dalam daftar tersebut. Kemudian memprosesnya, dimana proses tersebut adalah menampilkan kepada user. Prosedur loop untuk kasus ini dapat berbunyi :
   Public Sub Contoh1_ForEachNext()
      Dim vKode As Variant
   
      For Each vKode In Array(10, 15, 20)
         MsgBox vKode
      Next vKode
   End Sub

Proses yang terjadi pada prosedur di atas adalah :
  • Deklarasi variabel item loop bernama vKode yang akan menampung salah satu elemen dari daftar kode. Karena data akan berupa array, maka dipilihlah datatype Variant untuk variabel vKode.
  • Proses loop dimulai dengan mendefinisikan variabel penampung setiap elemen array [vKode] dan mendefinisikan grup data yang akan di-loop [Array(10, 15, 20)] pada baris berbunyi :
     For Each vKode In Array(10, 15, 20)
  • Baris tersebut memiliki arti bahwa setiap elemen dari Array(10, 15, 20) diproses satu persatu dengan meletakkannya di wadah bernama vKode
  • Proses loop pertama akan membuat vKode berisi elemen array pertama yang bernilai 10
  • Kemudian proses dalam loop dikerjakan, yaitu baris kode berbunyi :
     MsgBox vKode
  • Setelah itu, akan beralih ke elemen array berikutnya saat proses mencapai baris kode berbunyi :
     Next vKode
  • Karena masih ada elemen array yang belum pernah dimasukkan ke dalam vKode, maka terjadilah pengambilan elemen array tersebut dan memasukkannya ke dalam vKode. Jadi, vKode akan berubah isinya menjadi elemen array kedua yang bernilai 15.
  • Baris kode dalam blok loop kembali dikerjakan, yaitu menampilkan nilai vKode kepada user melalui baris kode :
     MsgBox vKode
  • Proses akan berlangsung demikian terus menerus sampai seluruh elemen array pernah diambil dan dimasukkan ke dalam variabel vKode
  • Ketika seluruh elemen array pernah diambil dan dimasukkan ke dalam vKode, maka proses loop selesai atau keluar dari blok loop
  • Proses akan beralih ke baris kode berikutnya. Ternyata baris kode berikutnya adalah akhir blok prosedur (END SUB), maka prosedur selesai dikerjakan

Contoh 2 :
Menampilkan nama worksheet dari setiap worksheet yang ada di dalam workbook. Pada kasus ini dapat diketahui bahwa grup data adalah berupa object collection, yaitu kumpulan worksheet dalam workbook. Setiap item dalam collection tersebut memiliki datatype object Worksheet. Jadi, variabel item dapat menggunakan datatype Worksheet. Prosedur untuk kasus ini dapat berbunyi :
   Public Sub Contoh2_ForEachNext()
      Dim sht As Worksheet
   
      For Each sht In ThisWorkbook.Worksheets
         MsgBox sht.Name
      Next sht
   End Sub

Proses yang terjadi pada prosedur di atas adalah :
  • Deklarasi variabel item bernama sht yang ber-datatype Worksheet karena grup data berupa object collection yang berisi object worksheet
  • Proses loop dimulai dengan mendefinisikan variabel penampung setiap item object collection [sht] dan mendefinisikan grup data yang akan di-loop [ThisWorkbook.Worksheets] pada baris berbunyi :
     For Each sht In ThisWorkbook.Worksheets
  • Baris tersebut memiliki arti bahwa setiap item Worksheet (karena datatype sht adalah Worksheet) dari kumpulan worksheet dalam workbook  diproses satu persatu dengan meletakkannya di wadah bernama sht
  • Proses loop pertama akan membuat sht berisi object worksheet dengan indeks 1 yang ada dalam workbook
  • Kemudian proses dalam loop, yang berupa menampilkan nama worksheet, dikerjakan. Proses tersebut adalah baris kode berbunyi :
     MsgBox sht.Name
  • Setelah itu, akan beralih ke item worksheet berikutnya saat proses mencapai baris kode berbunyi :
     Next sht
  • Jika masih ada item worksheet yang belum pernah dimasukkan ke dalam sht, maka terjadilah pengambilan item worksheet tersebut dan memasukkannya ke dalam sht. Jadi, sht akan berubah isinya menjadi object worksheet yang memiliki indeks 2 yang ada dalam workbook.
  • Baris kode dalam blok loop kembali dikerjakan, yaitu menampilkan nama worksheet kepada user melalui baris kode :
     MsgBox sht.Name
  • Proses akan berlangsung demikian terus menerus sampai seluruh item dalam object collection worksheet pernah diambil dan dimasukkan ke dalam variabel sht
  • Ketika seluruh item worksheet dalam object collection worksheet pernah diambil dan dimasukkan ke dalam sht, maka proses loop selesai atau keluar dari blok loop
  • Proses akan beralih ke baris kode berikutnya. Ternyata baris kode berikutnya adalah akhir blok prosedur (END SUB), maka prosedur selesai dikerjakan

Nested For Each

Seperti halnya blok loop lainnya, blok loop dengan FOR EACH juga bisa berada dalam blok loop lainnya, termasuk dalam blok loop dengan FOR EACH lainnya.

Bentuk dasarnya adalah :
   FOR EACH var_item1 IN grup_data1
      'baris kode yang di-loop untuk setiap var_item1
      FOR EACH var_item2 IN grup_data2
         'baris kode yang di-loop untuk setiap var_item2
      NEXT var_item2
      'baris kode yang di-loop untuk setiap var_item1   
   NEXT var_item1

Kaidah pemilihan datatype setiap var_item disesuaikan dengan grup_data masing-masing.

Contoh :
Menuliskan kombinasi nomor urut dan nomor kode. Nomor urut dari nomor 1 sampai 5. Nomor kode adalah 10, 15, dan 20. Setiap nomor urut akan mendapatkan setiap nomor kode. Ditulis pada sheet bernama 'Dataku' mulai baris 2, dengan nomor urut ditulis di kolom A (kolom ke-1 dalam sheet Dataku) dan nomor kode ditulis di kolom B (kolom ke-2 dalam sheet Dataku).

Kasus ini akan diselesaikan dengan FOR EACH seluruhnya, meskipun bisa dilakukan dengan blok loop lainnya. Pada kasus ini dapat diketahui bahwa :
  • Untuk nomor urut, akan ada grup data berupa array berisi angka 1 sampai 5
  • Setiap elemen array nomor urut akan dimasukkan ke wadah ber-datatype Variant yang diberi nama vNomor
  • Untuk nomor kode, akan ada grup data berupa array berisi angka-angka 10, 15, dan 20
  • Setiap elemen array nomor kode akan dimasukkan ke wadah ber-datatype Variant yang diberi nama vKode
  • Penulisan dilakukan ke sheet bernama Dataku mulai baris 2
  • Penulisan dimulai dari baris 2. Artinya dibutuhkan sebuah variabel penyimpan posisi penulisan, misalnya bernama lBaris dan akan dimulai dari nilai 2
  • Setiap nomor urut akan mendapatkan setiap nomor kode. Artinya bahwa loop terhadap array nomor kode ada di dalam loop terhadap array nomor urut
  • Penulisan nomor urut dan nomor kode dilakukan setiap pembacaan elemen array nomor kode atau di dalam blok loop terhadap array nomor kode.
  • Nilai lBaris akan bertambah 1 setiap selesai menuliskan nomor kode
  • Baris kode penambahan lBaris tersebut diletakkan dalam blok loop terhadap array nomor kode
Prosedur untuk contoh kasus ini dapat berbunyi :
   Public Sub Contoh1_NestedForEach()
      Dim vNomor As Variant, vKode As Variant
      Dim lBaris As Long
   
      lBaris = 2
      For Each vNomor In Array(1, 2, 3, 4, 5)

         For Each vKode In Array(10, 15, 20)
            Sheets("Dataku").Cells(lBaris, 1).Value = vNomor
            Sheets("Dataku").Cells(lBaris, 2).Value = vKode
           
            lBaris = lBaris + 1
         Next vKode

      Next vNomor
   End Sub


Keluar dari loop

Seringkali terjadi bahwa sebuah loop akan diarahkan untuk segera selesai atau proses segera keluar dari loop tanpa perlu menyelesaikannya sampai dengan item terakhir yang telah didefinisikan dalam baris definisi loop. Misalkan saja ketika melakukan loop terhadap suatu area range dan proses loop akan dihentikan ketika range tidak berisi suatu nilai. Pada dasarnya, ketika nilai yang di-loop tidak memenuhi ekspresi kondisi batas loop maka proses loop akan selesai atau dihentikan. Jadi, dengan mengubah nilai yang di-loop menjadi tidak memenuhi ekspresi kondisi adalah salah satu cara untuk keluar dari loop. Saat ini, cara ini umumnya digunakan hanya ketika menggunakan blok loop WHILE ... WEND. Blok loop FOR ... NEXT, FOR EACH, dan DO ... LOOP juga bisa menggunakan cara ini jika dikehendaki.

Khusus untuk blok loop FOR ... NEXT, FOR EACH dan DO ... LOOP dapat juga menggunakan statement yang sudah disediakan oleh VB/VBA, yaitu :
  • EXIT FOR untuk keluar dari blok loop yang menggunakan FOR (FOR ... NEXT atau FOR EACH)
  • EXIT DO untuk keluar dari blok loop yang menggunakan DO ... LOOP, meskipun pada beberapa kasus, batasan harus keluar dari loop bisa dijadikan salah satu elemen penyusun ekspresi kondisi dengan memanfaatkan statement logika seperti AND atau OR

Pada blok loop yang bersarang (nested loop), maka EXIT FOR atau EXIT DO akan keluar dari blok loop di level tersebut. Misal, EXIT FOR terletak pada blok loop dengan FOR ... NEXT yang ada di dalam blok loop dengan DO ... LOOP. Maka EXIT FOR akan membuat proses loop keluar dari blok loop dengan FOR ... NEXT. Meski demikian, proses loop pada blok DO ... LOOP masih bekerja karena blok loop ini berada dilevel lebih atas daripada blook loop dengan FOR ... NEXT.

Contoh 1 :
Menampilkan hasil penjumlahan nilai 1 sampai suatu nilai akhir tertentu yang tertinggi atau senilai 17. Prosedur loop untuk kasus ini bisa berbunyi :
1. Blok loop FOR ... NEXT
  • Menggunakan EXIT FOR
     Public Sub Contoh1_KeluarExitFor()
        Dim lNomor As Long, lTotal As Long, lAkhir As Long
   
        lAkhir = 5
        For lNomor = 1 To lAkhir
           lTotal = lTotal + lNomor
           If lTotal >= 17 Then
              lTotal = lTotal - lNomor
              Exit For
           End If
        Next lNomor
        MsgBox "Berhenti di lNomor = " & lNomor - 1 & vbCrLf & _
            "dengan lTotal = " & lTotal _
            , vbExclamation
     End Sub

  • Mengubah nilai yang di-loop
     Public Sub Contoh1_KeluarSetNilai()
        Dim lNomor As Long, lNomorReal As Long
        Dim lTotal As Long, lAkhir As Long
   
        lAkhir = 5
        For lNomor = 1 To lAkhir
           lTotal = lTotal + lNomor
           lNomorReal = lNomor
           If lTotal >= 17 Then
              lTotal = lTotal - lNomor
              lNomorReal = lNomor - 1
              lNomor = lAkhir
           End If
        Next lNomor
        MsgBox "Berhenti di lNomor = " & lNomorReal & vbCrLf & _
            "dengan lTotal = " & lTotal _
            , vbExclamation
     End Sub

Pada kedua prosedur di atas, proses loop akan berhenti ketika lTotal telah mencapai nilai 17 atau lebih atau ketika batas akhir loop tercapai. Kemudian menampilkan hasil penjumlahan kepada user menggunakan sebuah kotak pesan.
Perbedaan antara kedua prosedur adalah :
  • penggunaan baris EXIT FOR pada prosedur bernama Contoh1_KeluarExitFor dan menggunakan baris kode pengubah nilai loop menjadi nilai diluar area kerja loop yang berbunyi lNomor = lAkhir.
  • Nilai nomor urut saat nilai total tercapai dapat dihitung dengan pasti pada prosedur Contoh1_KeluarExitFor, yaitu dengan mengurangkannya dengan nilai interval yang diletakkan setelah statement STEP. Pada kasus ini, intervalnya menggunakan nilai default, yaitu 1, karena tidak ada statement STEP dalam prosedur.
  • Pada prosedur bernama Contoh1_KeluarSetNilai dibutuhkan sebuah variabel tambahan bernama lNomorReal untuk menyimpan nilai nomor urut untuk nilai total yang sedang dihasilkan, karena nilai lNomor akan diubah menjadi lAkhir agar proses loop bisa terhenti ketika batas nilai total telah tercapai.
  • Penambahan baris-baris kode untuk menentukan nilai lNomorReal akan menambah waktu proses yang akan terasa signifikan ketika melakukan loop terhadap data yang sangat banyak.


2. Blok loop DO ... LOOP
  • Menggunakan EXIT DO
     Public Sub Contoh2_KeluarExitDo()
        Dim lNomor As Long, lAkhir As Long
        Dim lTotal As Long
   
        lNomor = 1
        lAkhir = 5
        Do While lNomor <= lAkhir
           lTotal = lTotal + lNomor
           If lTotal >= 17 Then
              lTotal = lTotal - lNomor
              Exit Do
           End If
           lNomor = lNomor + 1
        Loop
        MsgBox "Berhenti di lNomor = " & lNomor - 1 & vbCrLf & _
            "dengan lTotal = " & lTotal _
            , vbExclamation
     End Sub

  • Mengubah nilai yang di-loop
     Public Sub Contoh2_KeluarSetNilai()
        Dim lNomor As Long, lNomorReal As Long
        Dim lTotal As Long, lAkhir As Long
   
        lNomor = 1
        lAkhir = 5
        Do While lNomor <= lAkhir
           lTotal = lTotal + lNomor
           lNomorReal = lNomor
           If lTotal >= 17 Then
              lTotal = lTotal - lNomor
              lNomorReal = lNomor - 1
              lNomor = lAkhir
           End If
           lNomor = lNomor + 1
        Loop
        MsgBox "Berhenti di lNomor = " & lNomorReal & vbCrLf & _
            "dengan lTotal = " & lTotal _
            , vbExclamation
     End Sub

  • Memasukkan batasan keluar kedalam ekspresi kondisi
     Public Sub Contoh2_KeluarEkspresiKondisi()
        Dim lNomor As Long, lNomorReal As Long
        Dim lTotal As Long, lAkhir As Long
   
        lNomor = 1
        lAkhir = 5
        Do While lNomor <= lAkhir And lTotal + lNomor <= 17
           lTotal = lTotal + lNomor
           lNomor = lNomor + 1
        Loop
        MsgBox "Berhenti di lNomor = " & lNomor - 1 & vbCrLf & _
            "dengan lTotal = " & lTotal _
            , vbExclamation
     End Sub

Perbedaan antara prosedur Contoh2_KeluarExitDo dengan Contoh2_KeluarSetNilai sama dengan perbedaan antara prosedur Contoh1_KeluarExitFor dengan Contoh2_KeluarSetNilai. Hanya saja, statement yang digunakan adalah EXIT DO dan bukan EXIT FOR. Pada prosedur Contoh2_KeluarEkspresiKondisi, batasan keluar dari loop dimasukkan ke dalam ekspresi kondisi. Batasan keluar loop adalah ketika nilai total ditambahkan nilai nomor yang baru masih di dalam batas nilai total yang ditentukan (17). Kondisi kerja loop juga dipengaruhi nilai nomor yang kurang dari atau sama dengan nilai akhir (lAkhir). Penggunaan statement logika AND untuk menghubungkan kedua kondisi tersebut disebabkan karena seluruh kondisi harus terpenuhi. Ekspresi kondisi yang terbentuk adalah :
   lNomor <= lAkhir And lTotal + lNomor <= 17
Blok loop yang digunakan untuk ekspresi kondisi di atas adalah DO WHILE

3. Blok loop WHILE ... WEND
     Public Sub Contoh3_KeluarWhileWend()
        Dim lNomor As Long, lNomorReal As Long
        Dim lTotal As Long, lAkhir As Long
   
        lNomor = 1
        lAkhir = 5
        While lNomor <= lAkhir And lTotal + lNomor <= 17
           lTotal = lTotal + lNomor
           lNomor = lNomor + 1
        Wend
        MsgBox "Berhenti di lNomor = " & lNomor - 1 & vbCrLf & _
            "dengan lTotal = " & lTotal _
            , vbExclamation
     End Sub

Prosedur Contoh3_KeluarWhileWend mirip dengan prosedur bernama Contoh2_KeluarEkspresiKondisi. Hanya berbeda jenis blok loop yang digunakan, yaitu WHILE ... WEND pada prosedur Contoh3_KeluarWhileWend dan DO WHILE ... LOOP pada prosedur Contoh2_KeluarEkspresiKondisi.

Contoh 2 :
Menampilkan hasil penjumlahan dari nilai-nilai yang ada di sheet bernama Dataku pada kolom Q mulai baris 1 sampai suatu cell di kolom Q tersebut adalah kosong. Prosedur loop untuk kasus ini bisa berbunyi :
   Public Sub Contoh4_KeluarForEach()
      Dim rng As Range, lTotal As Long
   
      For Each rng In Sheets("Dataku").Range("Q:Q")
         If Len(rng.Value) = 0 Then
            Exit For
         End If
         lTotal = lTotal + rng.Value
      Next rng
      MsgBox "lTotal = " & lTotal & vbCrLf & _
            "terakhir di baris " & rng.Row - 1 _
            , vbExclamation
   End Sub

Pada prosedur di atas, pemeriksaan tentang keberadaan isi suatu cell adalah dengan membandingkan bahwa jumlah karakter (LEN) di cell tersebut adalah 0. Hal ini dilakukan pada baris :
   If Len(rng.Value) = 0 Then
Ketika hasil pemeriksaannya adalah TRUE alias panjang karakter cell tersebut adalah 0, maka proses akan masuk ke dalam blok IF yang berisi baris kode untuk keluar blok FOR yang berbunyi :
   Exit For

Simpulan

Penggunaan FOR EACH bisa jadi akan lebih lambat dibandingkan penggunaan DO ... LOOP atau FOR ... NEXT pada kondisi-kondisi tertentu. Penggunaan grup data yang bisa diisi dengan data-data pilihan saja adalah salah satu yang membuat FOR EACH terasa begitu praktis dan efisien. Contohnya adalah pada hasil autofilter suatu tabel yang menghasilkan data yang tidak kontinyu baris-baris Excel-nya akan mudah dijadikan sebagai sebuah grup data, sehingga proses loop yang harus dilakukan pada hasil autofilter tersebut akan lebih sederhana jika menggunakan FOR EACH.

:)

Insya Allah pembahasan selanjutnya adalah tentang dasar-dasar dalam menggunakan object range. Hal ini mencakup tentang pemahaman LastCell, CurrentRegion, Offset, Resize, End xlUp atau End xlDown, dan sebagainya. Dasar-dasar dalam menggunakan object range akan memudahkan dalam mengolah data menggunakan VBA, karena menyusun rujukan yang dinamis membutuhkan pemahaman tentang cara menggunakan object range. Contohnya adalah menentukan batas bawah tabel data yang ada atau menentukan baris kosong pertama yang ada disebuah tabel data berkaidah database.




Tidak ada komentar:

Posting Komentar