Friday, December 16, 2016

Bab 3. VB.NET Untuk Programer



Koleksi



Bab ini mengintroduksi sejumlah kelas koleksi di dalam pustaka .NET, dengan ide bahwa koleksi objek dapat membantu membangun konsep-konsep yang nantinya dapat diterapkan pada database. Anda akan belajar bagaimana menciptakan dan menggunakan ArrayList, List, dan Dictionary. Bab ini akan menyajikan contoh-contoh bagaimana menggunakan teknologi LINQ (Language Integrated Query) untuk melakukan pencarian terhadap objek.


3.1 ArrayList
Dengan istilah yang paling umum, koleksi adalah sekelompok nilai yang beruntun atau tak-beruntun. Pada sebuah koleksi beruntun yang dikenal dengan list, nilai-nilai ditempatkan pada posisi-posisi yang relatif satu sama lain. Sebagai contoh, sebuah list yang memuat cuplik-cuplik suhu yang diambil setiap jam selama sehari. Array dapat dipandang sebagai list. Jenis lain dari koleksi adalah set, yang tidak memiliki runtun tertentu. Jenis lain dari koleksi adalah Dictionary atau map, yang melekatkan setiap kunci dengan nilai tertentu. Jika Anda ingin mencari transkript akademik dari seorang siswa, misalnya, Anda dapat menggunakan ID siswa sebagai kunci. Nilai yang berkaitan dengan tiap kunci di dalam kamus, pada kasus ini, adalah transkript siswa.

Pustaka .NET memiliki sejumlah kelas yang mengimplementasikan beberapa jenis koleksi. Pada bab ini, Anda akan mempelajari ArrayList, List, dan Dictionary.


Gambar 3.1 Relasi-relasi pada ArrayList


Kelas ArrayList
Koleksi .NET yang paling fundamental adalah kelas ArrayList, yang merupakan koleksi tipe-list yang dapat mengembang yang memuat referensi-referensi ke objek-objek. ArrayList merupakan bagian dari namespace System.Collections. Seperti array, ArrayList juga dapat menggunakan subskript untuk secara acak mengakses elemen-elemennya. ArrayList lebih tangguh dan fleksibel dari array biasa karena aspek-aspek berikut:
  • ArrayList akan mengembang atau membesar ketika item-item baru disisipkan, sedangkan array tidak bisa melakukannya.
  • ArrayList memuat metode-metode untuk melakukan pencarian, penyisipan, dan penghapusan item, sedangkan array tidak bisa melakukannya.

 Anda dapat menyisipna sejumlah objek berbeda tipe ke dalam objek ArrayList yang sama.


Gambar 3.1 menunjukkan beberapa relasi antara ArrrayList dengan item-item yang dimuatnya. Tabel 3.1 mencantumkan sejumlah properti dan metode dari ArrayList.

Tabel 3.1 Properti-properti dan metode-metode pada kelas ArrayList
Properti Atau Metode
Penjelasan
Add(elemen As Object)
Clear( )
Contains( elemen As Object ) As Boolean

Count( ) As Integer
Insert(indeks As Integer, elemen as Object)

Item( indeks As Integer ) As Object

Remove( elemen As Object )

RemoveAt( indeks As Integer )
Menambahkan sebuah item di akhir list
Menghapus semua item dari list
Menghasilkan True jika list memuat item yang ditentukan
Menghasilkan banyak item di dalam list
Menyisipkan sebuah item ke dalam list pada posisi indeks tertentu.
Menghasilkan sebuah referensi yagn menunjuk ke item list pada posisi indeks tertentu.
Menghapus kemunculan pertama dari item tertentu dari list.
Menghapus item pada posisi indeks tertentu.


Menciptakan Sebuah ArrayList
Anda menggunakan operator New untuk menciptakan sebuah objek dari kelas ArrayList. Sebagai contoh:

Dim konsumen As New ArrayList

Anda dapat pula melewatkan sebuah array, sebuah ArrayList, atau sembarang objek yang mengimplementasikan antarmuka ICollection kepada konstruktor ArrayList. Pada kode berikut, misalnya, ArrayList menerima sebuah salinan dari array skor:

Dim skor() As Integer = {80, 66, 75}
Dim skorList As New ArrayList(skor)


Menambah dan Menyisipkan Item
Salah satu cara dalam menambah item ke sebuah ArrayList adalah dengan memanggil metode Add. Berikut adalah contohnya:

konsumen.Add(“Bakri”)

Anda dapat pula menggunakan metode Insert untuk menempatkan sebuah item ke dalam list pada posisi tertentu:

skorList.Insert(1,”Roro Kusuma”)

Tidak ada batasan pada penyisipan item duplikat, jadi jika persyaratan aplikasi Anda tidak membolehkan adanya item duplikat, Anda perlu memeriksanya sendiri.


Menghapus Item
Metode RemoveAt menghapus sebuah item ArrayList. Anda dapat melewatkanya kepadanya posisi indeks dari item yang ingin dihapus. Statemen berikut menghapus sebuah item pada posisi indeks 2:

konsumen.RemoveAt(2)

Metode Remove menghapus item pertama yang cocok dengan item yang dilewatkan sebagai parameter masukan. Statemen berikut menghapus “Bakri” dari ArrayList konsumen:

konsumen.Remove(“Bakri”)

Mencari Item
Metode Contains menghasilkan sebuah nilai Boolean yang mengindikasikan apakah nilai tertentu ada di dalam sebuah ArrayList. Pada contoh berikut, variabel ditemukan akan bernilai True jika nilai 66 ada di dalam ArrayList dengan nama skorList:

Dim ditemukan As Boolean = skorList.Contains(66)

Metode IndexOf menghasilkan sebuah integer yang mengidentifikasi posisi indeks dari sebuah item. Jika item tidak ditemukan, nilai yang dihasilkan adalah -1. Kode berikut memanggil IndexOf dan menampilkan sebuah pesan jika nama konsumen tidak ditemukan:

Dim indeks As Integer = konsumen.IndexOf(“Bakri”)
If indeks = -1 Then
    labelStatus.Text = “Konsumen tidak ditemukan”
End If

Membaca dan Mengganti Item
Properti Item menghasilkan sebuah referensi yang menunjuk ke suatu elemen ArrayList. Anda melewatkan kepada properti Item sebuah indeks integer antara 0 dan ArrayList.Count-1. Sebagai contoh, kode berikut membaca nilai yang disimpan pada posisi indeks 2 pada ArrayList dengan nama konsumen:

Dim nama As String = CStr(konsumen.Item(2))

Karena ekspresi konsumen.Item(2) menghasilkan sebuah tipe data Object, Anda perlu mengkonversinya menjadi tipe String sebelum menugaskannya kepada variabel nama.

Item disebut pula sebagai properti default, jadi statemen berikut secara implisit membaca elemen pada posisi indeks 2:

Dim nama As String = CStr(konsumen(2))

Anda dapat menggunakan properti Item untuk mengganti sebuah item di dalam ArrayList. Kode berikut menunjukkan dua cara dalam mengganti item pada indeks 2 dengan “John”:

konsumen.Item(2) = “John”
konsumen(2) = “John”


Eksepsi IndexOutOfRangeException
Sebuah eksepsi IndexOutOfRangeException dilemparkan ketika Anda melewatkan sebuah indeks kepada properti Item yang tidak cocok dengan indeks dari setiap item di dalam sebuah ArrayList. Kode berikut menunjukkan bagaimana menangani eksepsi ini:

Try
    Dim indeks As Integer = CInt(teksIndeks.Text)
    Dim kons As String = CStr(konsumen.Item(indeks))
Catch ex As IndexOutOfRangeException
    MessageBox.Show(ex.Message)
End Try

Aturan yang sama berlaku ketika Anda memanggil metode RemoveAt, yang juga harus menerima indeks yang valid.

Properti Count
Properti Count mengindikasikan banyak item yang disimpan di dalam sebuah ArrayList. Kode berikut menggunakan properti Count untuk menampilkan ukuran dari list konsumen:

labelInfo.Text = “Ukuran koleksi adalah “ & konsumen.Count

Loop
Cara mudah untuk menjelajak ArrayList adalah dengan menggunakan statemen For Each. Selama tiap iterasi, variabel yang dideklarasikan di dalam loop merepresentasikan nilai item terkini. Kode berikut menjelajah skorList dan menambahkan tiap skor pada sebuah kotak list:

For Each skor As Integer In skorList
    kotakList.Items.Add(skor)
Next

Sama halnya, kode berikut menjelajah ArrayList dengan nama konsumen dan menambahkan tiap elemennya pada sebuah kotak list:

For Each kons As String In konsumen
    kotakList.Items.Add(kons)
Next



Pada Tutorial 3.1, Anda akan menciptakan sebuah aplikasi yang membangun suatu ArrayList yang memuat sejumlah skor ujian.

Tutorial 3.1: ArrayList yang Memuat Sejumlah Skor Ujian
Pada tutorial ini, Anda akan menciptakan sebuah aplikasi yang memiliki sebuah kelas Siswa yang memuat sebuah ArrayList yang terdiri-dari sejumlah skor ujian. Ketika tiap skor ujian dimasukkan oleh user, ia akan ditambahkan pada list. Sebuah properti ReadOnly di dalam kelas akan menghitung rerata ujian. Kelas juga memuat sebuah variabel shared yang memuat nama sekolah, dengan sebuah properti shared terkait.

Gambar 3.2 menunjukkan keluaran aplikasi setelah user memasukkan ID siswa dan nama, dan telah mengklik tombol Simpan. Kemudian, ketika user memasukkan sejumlah skor ujian dan mngklik tombol Lihat, contoh keluaran ditampilkan pada Gambar 3.3. User dapat melanjutkan memasukkan skor ujian lainnya dan mengklik tombol Lihat sebanyak yang diinginkan.


Gambar 3.2 Setelah mengklik tombol Simpan


Gambar 3.3 Setelah user menambahkan dua skor dan mengklik tombol Lihat


Langkah-Langkah Tutorial
Langkah 1: Buka projek Koleksi Skor Ujian. Kontrol-kontrol diberinama berikut:
·         Kontrol-kontrol TextBox: teksNomorID, teksNamaBelakang, dan teksNilai
·         Kontrol-kontrol Label: labelRerataUjian, labelSiswa, dan labelSekolah
·         Kontrol-kontrol Button: tombolTambahkan, tombolSimpan, dan tombolLihat.

Langkah 2: Buka kelas Siswa pada editor kode dan lihat kode berikut:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Public Class Siswa
    Public Property NomorId As String
    Public Property NamaBelakang As String
    Public Shared Property NamaSekolah As String
    Private mSkorUjian As New ArrayList

    Public ReadOnly Property RerataUjian() As Double
        Get
            Dim jumUjian As Double = 0.0
            For Each nilai As Double In mSkorUjian
                jumUjian += nilai
            Next
            If mSkorUjian.Count > 0 Then
                Return jumUjian / mSkorUjian.Count
            Else
                Return 0.0
            End If
        End Get
    End Property

ArrayList dideklarasikan pada baris 5. Baris 13 memeriksa nilai dari mSkorUjian.Count, untuk menghindari pembagian dengan nol ketika tidak ada skor ujian yang ditambahkan pada koleksi. Baris 14 menghitung dan menghasilkan rerata ujian.

Metode-metode yang memuat sebuah konstruktur, sebuah metode untuk menambahkan nilai ujian pada koleksi, dan sebuah metode ToString:

   Public Sub New(ByVal pNomorId As String,
      Optional ByVal pNamaBelakang As String = "")
        NomorId = pNomorId
        NamaBelakang = pNamaBelakang
    End Sub

    Public Sub TambahkanNilaiUjian(ByVal nilai As Double)
        mSkorUjian.Add(nilai)
    End Sub

    Public Overrides Function ToString() As String
        Return NomorId & ", " & NamaBelakang
    End Function
End Class

Langkah 3: Buka jendela Code untuk Form1.vb dan periksa kode berikut:

Public Class Form1
    Private objSiswa As Siswa

Event handler Form1_Load menetapkan nilai dari properti shared NamaSekolah di dalam kelas Siswa:

Private Sub Form1_Load(…) Handles MyBase.Load
    Siswa.NamaSekolah = "Sekolah Tarabunga"
End Sub

Langkah 4: Lihat handler Click untuk tombol Simpan:

Private Sub tombolSimpan_Click(…) Handles tombolSimpan.Click
    objSiswa = New Siswa(teksNomorID.Text, teksNamaBelakang.Text)
    labelSiswa.Text = "(informasi siswa telah disimpan)"
    tombolTambahkan.Enabled = True
End Sub

Metode ini menciptakan sebuah objek Siswa yang baru dari dua kotak teks. Perhatikan bagaimana tombol Tambahkan diaktifkan hanya ketika user mengklik tombol Simpan. Ini perlu untuk mencegah program mencoba menjumlahkan skor sebelum sebuah objek Siswa diciptakan. Tombol Tambahkan dipakai user untuk menjumlahkan skor-skor ujian pada koleksi skor dari siswa terkait.

Langkah 5: Lihat handler Click untuk tombol Lihat, yang menampilkan ID siswa dan nama belakangnya, nama sekolah, dan rerata ujian siswa:

Private Sub tombolLihat_Click(…) Handles tombolLihat.Click
        labelSiswa.Text = objSiswa.ToString
        labelSekolah.Text = Siswa.NamaSekolah
        labelRerataUjian.Text = objSiswa.RerataUjian.ToString("n")
    End Sub

Langkah 6: Event handler Click untuk tombol Tambahkan mengambil nilai ujian dari kotak teks teksNilai dan memanggil metode Siswa.TambahkanNilaiUjian. Metode ini menambahkan nilai pada koleksi nilai dari mahasiswa:

Private Sub tombolTambahkan_Click(…) Handles tombolTambahkan.Click
    Dim nilaiUjian As Double
    If Double.TryParse(teksNilai.Text, nilaiUjian) Then
        objSiswa.TambahkanNilaiUjian(nilaiUjian)
    Else
        MessageBox.Show("Nilai ujian harus berupa angka", "Error")
    End If
End Sub

Langkah 7: Simpan projek dan jalankan aplikasi.


3.2 ArrayList yang Memuat Objek-Objek
Anda telah melihat bagaimana menciptakan ArrayList yang memuat tipe-tipe standar, seperti String dan Double. Anda juga dapat menciptakan list yang memuat objek-objek dari kelas Anda sendiri. Dimisalkan bahwa Anda ingin menciptakan sebuah list yang memuat objek-objek Siswa. Pekerjaan-pekerjaan berikut dilakukan pada list:
·         Menjelajah list dan menampilkan tiap siswa
·         Melakukan pencarian siswa
·         Mengurutkan list
·         Menghapus sebuah siswa dari list

Anda harus menciptakan sebuah objek baru dari kelas Siswa setiap kali Anda menyisipkan sebuah objek baru, untuk menghindari penciptaan sebuah ArrayList dimana di dalamnya semua item mereferensi objek yang sama. Selain itu, kelas Siswa perlu mengimplementasikan metode Equals dan CompareTo.

Referensi dan Salinan
Ketika sebuah item di dalam suatu ArrayList adalah sebuah tipe nilai seperti Integer atau Single, metode Item menghasilkan salinan item. Sebagai contoh, kode berikut menyisipkan sebuah integer ke dalam suatu ArrayList dengan nama angka:

Dim angka As New ArrayList
angka.Add(10)

Selanjutnya, kode berikut membaca integer yang disimpan pada indeks 0 dan memodifikasi nilainya:

Dim intNil As Integer = CType(angka.Item(0), Integer)
intNil = 99

Tetapi intNil hanyalah salinan dari item pada koleksi, jadi item yang disimpan di dalam ArrayList pada indeks 0 sama dengan nilai awalnya, 10.

Tetapi ketika sebuah item di dalam ArrayList adalah tipe referensi, metode Item menghasilkan referensi yang menunjuk ke objek. Referensi dapat dipakai untuk memodifikasi objek di dalam list. Untuk mengilustrasikannya, Anda dapat menciptakan sebuah ArrayList dengan nama siswa dan menyisipkan sebuah objek Siswa:

Dim siswa As New ArrayList
siswa.Add(New Siswa(“Kristof”))

Selanjutnya, Anda menggunakan metode Item untuk mendapatkan sebuah referensi yang menunjuk ke siswa yang sama:

Dim siswaRef as Student = CType(siswa.Item(0), Siswa)

Selanjutnya, Anda menugaskan sebuah nama belakang baru kepada referensi siswa:

siswaRef.NamaBelakang = “Bening”

Dengan melakukannya, Anda juga telah memodifikasi nama dari objek Siswa yang ada di dalam ArrayList. Ini karena metode Item menghasilkan referensi ke objek di dalam ArrayList.

Error yang Sering Terjadi: Beberapa Referensi ke Objek yang Sama
Dengan memahami bagaimana referensi bekerja, Anda dapat terhindar dari error yang sering terjadi ketika bekerja dengan koleksi, yaitu error yang menyimpan beberapa referensi yang menunjuk ke objek yang sama. Kode berikut (ditempatkan di dalam handler Click untuk sebuah tombol dengan nama Tambahkan) menunjukkan cara tepat untuk menyisipkan sebuah objek ke dalam ArrayList:

1
2
3
4
5
6
7
Private SemuaSiswa As New ArrayList

Private Sub tombolTambahkan_Click() Handles tombolTambahkan.Click
    Dim objSiswa As New Siswa(teksNomorID.Text,
    teksNamaBelakang.Text, CDbl(teksRerataUjian.Text))
    SemuaSiswa.Add(objSiswa)
End Sub

Baris 4 menciptakan sebuah objek Siswa yang baru, dengan menggunakan nilai dari tiap kotak teks. Baris 6 menambahkan siswa tersebut ke dalam ArrayList. Selanjutnya, lihat kode yang sama yang memuat error yang sering dilakukan:

1
2
3
4
5
6
7
8
9
Private SemuaSiswa As New ArrayList
Private objSiswa As New Siswa

Private Sub tombolTambahkan_Click() Handles tombolTambahkan.Click
    objSiswa.NomorID = teksNomorID.Text
    objSiswa.NamaBelakang = teksNamaBelakang.Text
    objSiswa.RerataUjian = CDbl(teksRerataUjian.Text)
    SemuaSiswa.Add(objSiswa)
End Sub

Dapatkah Anda melihat errornya? Satu objek Siswa diciptakan pada baris 2. Kemudian, pada baris 5-7, properti-propertinya ditugasi nilai-nilai dari kotak-kotak teks. Pada baris 8, objek ditambahkan ke dalam ArrayList. Tetapi setiap kali loop beriterasi, baris 8 menambahkan objek Siswa yang sama ke dalam ArrayList. Entri-entri di dalam ArrayList akan mereferensi objek yang sama, seperti ditunjukkan pada Gambar 3.4. Jadi pelajaran yang diambil dari contoh ini adalah bahwa Anda harus menciptakan objek baru setiap kali Anda menyisipkan sebuah objek ke dalam suatu ArrayList.

Gambar 3.4 Ketika anggota-anggota ArrayList mereferensi objek yang sama


Membandingkan Objek-Objek dengan CompareTo
Ketika Anda mengurutkan array atau ArrayList yang memuat objek-objek dari kelas sendiri, Anda perlu mendefinisikan bagaimana entri-entri dibandingkan, menggunakan sebuat metode dengan nama CompareTo. Metode ini memiliki daftar parameter dan tipe nilai balik berikut:

Function CompareTo(ByVal obj As Object) As Integer

Jika diberikan dua objek A dan B, metode CompareTo dipanggil seperti ini:

Dim hasil As Integer = A.CompareTo(B)

Nilai balik dari CompareTo ketika membandingkan dua objek A dan B adalah berikut:
·         Jika A kurang dari B, maka A.CompareTo(B) menghasilkan sebuah integer negatif.
·         Jika A sama dengan B, maka A.CompareTo(B) menghasilkan nol.
·         Jika A lebih dari B, maka A.CompareTo(B) menghasilkan sebuah integer positif.

Jika sebuah kelas tidak memiliki metode CompareTo, semua objek dari kelas itu tidak dapat diurutkan. Dengan kata lain, objek-objek itu tidak komparabel. Untuk mendemonstrasikannya, diciptakan kelas Siswa berikut:

Class Siswa
    Public Property Id As String
    Public Property Nama As String

    Public Sub New(ByVal pId As String, ByVal pNama As String)
        Id = pId
       Nama = pNama
    End Sub
End Class

Selanjutnya, Anda menyisipkan elemen-elemen ke dalam ArrayList dan mencoba untuk mengurutkannya:

Dim list = New ArrayList()
list.Add(New Siswa(“2001”, ”John”))
list.Add(New Siswa(“1004”, ”Kristof”))
list.Add(New Siswa(“1050”, ”Adam”))
list.Sort()

Setelah aplikasi dijalankan, eksepsi yang tidak tertangani akan pada Gambar 3.5 akan mengatakan: Failed to compare two elements in the array. Dengan  kata lain, Anda gagal mencantumkan sebuah metode CompareTo di dalam kelas Siswa. Tetapi, sebelum menunjukkan bagaimana menciptakan metode CompareTo, Anda perlu memahami tentang antarmuka pada pustaka .NET.

Gambar 3.5 Mencoba mengurutkan sebuah ArrayList


Antarmuka
Sebuah antarmuka mendefinisikan sejumlah metode dan properti yang dapat diimplementasikan oleh kelas-kelas lain. Kelas yang mengimplementasikan antarmuka akan dijamin memuat metode-metode dan properti-properti tersebut. Ketika sebuah kelas mengimplementasikan suatu antarmuka, Anda belajar hal penting tentang kelas: Anda akan belajar apa yang bisa dilakukan oleh kelas itu.

Antarmuka dideklarasikan dengan cara yang hampir sama dengan kelas. Sebagai contoh, berikut adalah bagaimana .NET mendefinisikan antarmuka IComparable:

Interface IComparable
Function CompareTo(ByVal obj As Object) As Integer
End Interface

Perhatikan bahwa metode CompareTo tidak memuat tubuh, hanya sidik metode. Sidik metode memuat kata Sub atau Function, yang diikuti dengan nama metode, daftar parameter, dan tipe nilai balik (jika ia adalah sebuah fungsi).

Jika sebuah kelas mengimplementasikan antarmuka IComparable, kelas itu harus memuat sebuah metode CompareTo dengan sidik yang sama dengan yang didefinisikan di dalam antarmuka IComparable. Selain itu, metode CompareTo di dalam kelas pengimplementasi antarmuka IComparable harus memuat sebuah tubuh. Selain itu, Anda akan mempelajari bagaimana kelas Siswa dapat mengimplementasikan antarmuka IComparable.

Contoh CompareTo
Dimisalkan bahwa Anda telah menciptakan kelas Siswa, dan Anda ingin membandingkan objek-objek Siswa berdasarkan nomor ID. Kemudian kelas Siswa tersebut akan mengimplementasikan antarmuka IComparable. Kode berikut menunjukkan bagian-bagian yang berelasi dengan antarmuka IComparable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Class Student
    Implements IComparable
    Public Property Id As String
    Public Property NamaBelakang As String

    Public Sub New(ByVal pId As String, ByVal pNama As String)
       Id = pId
       NamaBelakang = pNama
    End Sub

    Public Function CompareTo(ByVal obj As Object) As Integer
      Implements IComparable.CompareTo
          Dim S As Siswa = CType(obj, Siswa)
          Return Me.Id.CompareTo(S.Id)
    End Function
 End Class

Baris 2 menyatakan bahwa kelas ini mengimplementasikan antarmuka IComparable. Baris 11 menyatakan bahwa metode CompareTo di dalam kelas ini mengimplementasikan metode CompareTo yang ditetapkan di dalam antarmuka IComparable. Baris 12 mengkonversi parameter obj menjadi sebuah objek Siswa, sehingga Anda dapat mengakses bidang Id pada baris 13. Pada baris itu, nilai Id dari siswa sekarang (diidentifikasi dengan Me) dibandingkan dengan nilai Id dari siswa yang dilewatkan sebagai parameter pada metode ini. (Pengkualifikasi Me tidak diharuskan, tetapi ia dapat memperjelas objek mana yang mana).

Metode CompareTo tampak sangat mirip pada setiap kelas yang mengimplementasikannya. Hanya beberapa baris kode yang spesifik dengan tipe objek yang sedang dibandingkan. Sebagai contoh, jika Anda membandingkan dua objek Akun berdasarkan saldonya, metode CompareTo akan tampak seperti ini:

Public Function CompareTo(ByVal obj As Object) As Integer
  Implements IComparable.CompareTo
      Dim A As Akun = CType(obj, Akun)
      Return Me.Saldo.CompareTo(A.Saldo)
End Function

Jika Anda berpikir bahwa Anda perlu mengurutkan sebuah ArrayList, maka setiap tipe objek yang ditempatkan ke dalam ArrayList tersebut harus merupakan sebuah objek dari suatu kelas yang mengimplementasikan IComparable. Aturan yang sama berlaku untuk array yang memuat objek-objek. Hal itu tidak masalah, karena IComparable mudah diimplementasikan dan sangat menolong.

Antarmuka IList dan IListSource
Adalah memungkinkan untuk menugaskan sebuah objek Array, ArrayList, dan List kepada properti DataSource dari ListBox, tetapi Anda tidak melakukannya dengan tipe objek lain. Sembarang objek yang ditugaskan kepada properti DataSource harus mengimplementasikan antarmuka IList atau IListSource. Ketika hal itu terjadi, kelas Array, ArrayList, dan List mengimplementasikan IList, yang memuat metode Contains, Add, IndexOf, Insert, Remove, dan RemoveAt.

Anda dapat pula menugaskan sebuah DataTable kepada properti DataSource dari ListBox karena kelas DataTable mengimplementasikan antarmuka IListSource.

Membandingkan Objek-Objek dengan Metode Equals
Anda telah belajar pada Bab 1 bahwa metode Equals membandingkan semua tipe standar .NET. Ia akan menghasilkan nilai True jika objek-objek memuat nilai sama. Untuk dua string di bawah ini, ekspresi A.Equals(B) bernilai True:

Dim A As String = “abcde”
Dim B As String = “'abcde”
A.Equals(B) 'True

Tetapi metode Equals tidak secara otomatis dikonfigurasi untuk kelas Anda sendiri. Contoh kode berikut membandingkan dua objek Siswa. Diasumsikan bahwa Anda belum menciptakan versi dari metode Equals di dalam kelas Siswa. Ekspresi s1.Equals(s2) bernilai False:

Dim s1 As New Siswa(1001)
Dim s2 As New Siswa(1001)
s1.Equals(s2) 'False

Secara natural, adalah sangat menolong untuk membandingkan objek-objek Siswa atau objek-objek tipe sendiri lainnya dengan cara yang mudah. Anda bisa saja ingin melakukan pencarian terhadap objek Siswa di dalam sebuah ArrayList dengan memanggil Contains atau IndexOf, misalnya. Untuk melakukannya, Anda harus mendefinisikan-ulang metode Equals di dalam kelas Siswa.

Mendefinisikan-Ulang Metode Equals
Untuk mendefinisikan-ulang metode Equals, Anda perlu menciptakan sebuah metode Equals di dalam kelas Anda sendiri dengan sidik yang sama dengan metode Equals di dalam kelas Object. Sidik dari metode Equals ditampilkan di sini:

Public Overrides Function Equals(ByVal obj As Object) As Boolean

Kelas Siswa berikut memuat sebuah metode Equals yang membandingkan siswa-siswa berdasarkan nomor ID:

1
2
3
4
5
6
7
8
Class Siswa
    Public Property Id As String
    Public Property NamaBelakang As String

    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        Return Me.Id.Equals(CType(obj, Siswa).Id)
    End Function
End Class

Baris 6 mengkonversi variabel obj menjadi sebuah objek Siswa, dan membaca nilai properti Id dari objek itu. Nilai ini dibandingkan dengan Me.Id, yaitu ID dari objek Siswa sekarang (objek pemanggil). Metode Equals ini menghasilkan True jika dua siswa memiliki nomor ID yang sama.

Anda dapat menyeleksi sembarang properti, variabel, atau nilai terhitung untuk dibandingkan ketika mengimplementasikan metode Equals. Secara umum, Anda sebaiknya memilih sebuah properti atau gabungan properti yang akan secara unik mengidentifikasi tiap objek.


Pada Tutorial 3.2, Anda akan menciptakan sebuah aplikasi yang menyisipkan objek-objek Siswa ke dalam sebuah ArrayList. Kelas Siswa memuat sebuah metode Equals yang membandingkan nomor ID.

Tutorial 3.2: Menciptakan sebuah ArrayList yang memuat objek-objek Siswa
Pada tutorial ini, Anda akan menciptakan sebuah aplikasi yang menciptakan sebuah ArrayList yang memuat objek-objek Siswa. Kelas Siswa akan mengimplementasikan metode Equals.

Langkah-Langkah Tutorial
Langkah 1: Buka projek dengan nama Koleksi Siswa.

Langkah 2: Jalankan aplikasi, masukkan nilai-nilai berikut ke dalam kotak-kotak teks, dan klik tombol Tambahkan ke Koleksi:

ID Siswa                   10000
Nama Belakang               Kristof
Rerata Ujian                82.5

Langkah 3: Masukkan dua siswa lagi, menggunakan data berikut, dan klik tombol Tambahkan ke Koleksi:

10001, Jonas, 90
10002, Rumiris, 79.5

Langkah 4: Klik tombol Lihat Semua. Gambar 3.6 menunjukkan keluaran yang diharapkan.


Gambar 3.6 Setelah menyisipkan tiga Siswa ke dalam koleksi


Langkah 5: Selanjutnya, Anda akan melakukan pencarian siswa berdasarkan nomor ID. Masukkan 10002 ke dalam TextBox di sudut kiri bawah, dan klik pada tombol Cari dengan ID. Program akan mencari siswa yang cocok dan menampilkannya pada ListBox, seperti ditunjukkan pada Gambar 3.7.


Gambar 3.7 Setelah melakukan pencarian siswa berdasarkan nomor ID


Langkah 6: Masukkan nomor ID yang tidak ada ke dalam kotak teks di pojok kiri bawah dari form dan klik tombol Cari dengan ID. Sebuah pesan akan ditampilkan bahwa siswa yang dicari tidak ada.

Langkah 7: Periksa kode sumber untuk kelas Siswa. Ia memiliki properti Id, NamaBelakang, RerataUjian, sebuah konstruktor, sebuah metode ToString, dan sebuah metode Equals.

Public Class Siswa
    Public Property Id As String
    Public Property NamaBelakang As String
    Public Property RerataUjian As Double

    Public Sub New(ByVal pId As String,
    Optional ByVal pNamaBelakang As String = "",
    Optional ByVal pRerataUjian As Double = 0.0)
        Id = pId
        NamaBelakang = pNamaBelakang
        RerataUjian = pRerataUjian
    End Sub

    Public Overrides Function ToString() As String
        Return Id & ", " & NamaBelakang &
         ", Rerata ujian = " & RerataUjian.ToString("n2")
    End Function

    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        Dim lain As Siswa = CType(obj, Siswa)
        Return Id = lain.Id
    End Function
End Class

Langkah 8: Periksa kode sumber untuk kelas Form1. Metode tombolTambahkan_Click menciptakan sebuah objek Siswa dan menambahkannya pada koleksi. Metode tombolLihat_Click menjelajah koleksi dan menyisipkan setiap item ke dalam ListBox. Metode tombolCari_Click melakukan pencarian sebuah siswa berdasarkan ID dan menampilkan Siswa yang cocok pada ListBox.

1
2
3
4
5
6
7
8
9
10
11
12
Public Class Form1
    Private semuaSiswa As New ArrayList

    Private Sub tombolTambahkan_Click(…) Handles tombolTambahkan.Click
        Try
            Dim objSiswa As New Siswa(teksIDSiswa.Text,
              teksNamaBelakang.Text, CDbl(teksRerataUjian.Text))
            semuaSiswa.Add(objSiswa)
        Catch
            MessageBox.Show("Rerata ujian tak valid", "Error")
        End Try
    End Sub

Baris 6-7 menciptakan sebuah siswa dari isi dari kotak-kotak teks, dan baris 8 menyisipkan siswa tersebut ke dalam ArrayList dengan nama semuaSiswa.

Baris 9: Lanjut pada kelas yang sama, lihat handler Click untuk tombol Lihat.

1
2
3
4
5
6
    Private Sub tombolLihat_Click(…) Handles tombolLihat.Click
        listSiswa.Items.Clear()
        For Each sis As Siswa In semuaSiswa
            listSiswa.Items.Add(sis.ToString)
        Next
    End Sub

Metode ini membersihkan kotak list dan menggunakan sebuah statemen For Each untuk menjelajah ArrayList. Setiap siswa disisipkan ke dalam kotak list listSiswa.

Langkah 10: Lihat handler Click untuk tombol Cari.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    Private Sub tombolCari_Click(…) Handles tombolCari.Click
        listSiswa.Items.Clear()
        Dim S As New Siswa(teksCariID.Text)
        Dim indeks As Integer = semuaSiswa.IndexOf(S)
        If indeks <> -1 Then
            S = CType(semuaSiswa(indeks), Siswa)
            listSiswa.Items.Add(semuaSiswa(indeks).ToString)
            'memperbarui kotak-kotak teks, agar konsisten
            teksIDSiswa.Text = S.Id
            teksRerataUjian.Text = S.RerataUjian.ToString("n")
            teksNamaBelakang.Text = S.NamaBelakang
        Else
            listSiswa.Items.Add("ID siswa tidak ditemukan")
        End If
    End Sub
End Class


Lihat beberapa detil pada kode ini. Baris 3 menciptakan sebuah objek Siswa dari nomor ID pada kotak teks teksCariID, dan baris 4 memanggil metode IndexOf untuk melakukan pencarian siswa di dalam ArrayList. Jika indeks yang dihasilkan oleh IndexOf tidak sama dengan 1, maka baris 6 akan membaca sebuah referensi yang menunjuk ke objek Siswa yang cocok di dalam list. Karena nilai yang dihasilkan oleh semuaSiswa(indeks) adalah tipe Object, maka Anda perlu mengkonversinya menjadi tipe Siswa. Kemudian, baris 7 menambahkan siswa itu pada kotak list. Baris 9-11 menyalin nilai-nilai properti siswa ke dalam kotak-kotak teks pada form, sehingga akan ditampilkan data yang sama seperti pada kotak list.


3.3 Kelas List dan Dictionary
Kelas ArrayList tidak membatasi tipe-tipe item yang dapat disisipkan ke dalam list. Oleh karena itu, Anda dapat mengatakan bahwa ArrayList merupakan koleksi bertipe lemah. Meskipun ini sepertinya merupakan keuntungan karena ia menawarkan fleksibilitas untuk menciptakan sebuah koleksi yang memuat pelbagai tipe objek, hal itu dapat menyebabkan error runtime yang tidak diinginkan. Sebagai contoh, sebuah aplikasi dapat melemparkan eksepsi jika suatu referensi yang menunjuk ke salah satu anggota ArrayList berbeda tipe dari yang diharapkan. Pada kasus itu, pemanggilan terhadap metode CType dapat menyebabkan eksepsi InvalidCastException.

Contoh Eksepsi InvalidCastException
Berikut adalah sebuah contoh yang menunjukkan bagaimana koleksi tipe lemah di dalam sebuah ArrayList dapat menyebabkan masalah.

Pada kode berikut, objek Siswa dan objek Pekerja disisipkan ke dalam ArrayList yang sama dengan nama listKu:

Class Siswa
    '...
End Class

Class Pekerja
    '...
End Class

Sub Uji()
    Dim listKu As New ArrayList
    listKu.Add(New Siswa)
    listKu.Add(New Pekerja)

    'baris berikutnya akan melemparkan eksepsi
    For Each item As Siswa In listKu
        kotakList.Add(item.ToString())
    Next
End Sub

Tetapi ketika kode tersebut menjelajah list dengan statemen For Each, eksepsi InvalidCastException akan dilemparkan. Gambar 3.8 menunjukkan pesan error yang dihasilkan. Error konversi seperti ini sangat sulit untuk ditangkap. Aplikasi bisa saja dapat bekerja dengan baik selama test tertentu. Tetapi di kemudian waktu, suatu runtun masukan tertentu dapat menyebabkan aplikasi gagal. Tentu ada solusi untuk ini. Anda dapat mengapit setiap statemen For Each dengan statemen Try dan Catch yang akan menangkan jenis error konversi semacam ini. Tetapi hal itu akan menambah pekerjaan dan perencanaan. Untuk menghindari jenis error konversi seperti ini, bahasa pemrograman modern mendukung keberadaan koleksi bertipe kuat.

Gambar 3.8 InvalidCastException


Koleksi Bertipe Kuat
Koleksi bertipe kuat merupakan sebuah koleksi yang hanya memuat satu tipe objek. Cara yang paling umum untuk mengimplementasikan koleksi semacam itu adalah melalui penggunaan kelas-kelas generik, yang dapat ditemukan di dalam namespace Systems.Collections.Generic. Kelas generik adalah sebuah kelas yang hanya mengampil satu tipe data ketika sebuah objek kelas diciptakan.

Tabel 3.2 menjelaskan sejumlah kelas generik yang berkaitan dengan list dan kamus, yang akan didemonstrasikan pada bab ini. Pustaka .NET memuat sejumlah kelas generik, yang dapat Anda baca pada dokumentasi online pada http://msdn.microsoft.com.

Tabel 3.2 Kelas-kelas di dalam namespace System.Collections.Generic
Kelas atau Struktur
Penjelesan
List(Of Tipe)

Dictionary(Of TipeKunci, TipeNilai)


SortedDictionary(Of TipeKunci, TipeNilai)


KeyValuePair(Of TipeKunci, TipeNilai)
Sebuah list sekuensial yang memuat objek-objek yang bertipe sama.

Sebuah kelas yang merepresentasikan koleksi kunci dan nilai. Kunci harus unik. Setiap nilai berkaitan dengan satu kunci.

Sebuah kamus dimana di dalamnya kunci-kunci ditata secara terurut.

Merepresentasikan sebuah entri Dictionary.

List (Of Tipe)
List(Of Tipe) adalah sebuah kelas yang memuat koleksi item sekuensial bertipe kuat. Kelas ini dipakai sebagai pengganti kelas ArrayList, yang memiliki metode-metode dan properti-properti yang hampir sama dengan kelas ArrayList. Kelas List(Of Tipe) menegakkan pemeriksaan tipe yang tegas pada item-item yang Anda sisipkan ke dalamnya. Tabel 3.3 mencantumkan sejumlah properti dan metode dari kelas ini.

Tabel 3.3 Sejumlah properti dan metode dari kelas List(Of Tipe)
Properti Atau Metode
Penjelasan
Add(elemen As Tipe)
Clear( )
Contains(elemen As Tipe) As Boolean

Count( ) As Integer
Insert(indeks As Integer, elemen as Tipe)

Item( indeks As Integer ) As Tipe

Remove( elemen As Tipe)

RemoveAt( indeks As Integer )
Sort()
ToArray()
Menambahkan sebuah item di akhir list
Menghapus semua item dari list
Menghasilkan True jika list memuat item yang ditentukan
Menghasilkan banyak item di dalam list
Menyisipkan sebuah item ke dalam list pada posisi indeks tertentu.
Menghasilkan sebuah referensi yagn menunjuk ke item list pada posisi indeks tertentu.
Menghapus kemunculan pertama dari item tertentu dari list.
Menghapus item pada posisi indeks tertentu.
Mengurutkan list.
Menghasilkan sebuah array bertipe kuat yang memuat objek-objek dari ArrayList.

Contoh: List yang memuat integer-integer
Kode berikut mendeklarasikan sebuah objek List(Of Integer) dan menambahkan tiga integer pada list tersebut:

Dim intList As New List(Of Integer)
intList.Add(30)
intList.Add(10)
intList.Add(20)

Metode Clear menghapus semua item.

intList.Clear()

Properti Item membaca sebuah referensi ke suatu item list, menggunakan indeks untuk mengidentifikasi posisi item:

Dim X As Integer = intList.Item(1)

Statemen For Each menjelajah sebuah List. Kode berikut menyalin item-item List ke dalam sebuah ListBox:

For Each M As Integer In intList
    kotakList.Items.Add(M)
Next

Metode Contains menghasilkan True jika ditemukan sebuah nilai yang cocok:

Dim ditemukan As Boolean = intList.Contains(20)

Metode IndexOf menghasilkan posisi indeks dari sebuah item cocok, atau -1 jika item tidak ditemukan:

Dim indeks As Integer = intList.IndexOf(20)

Metode Remove menghapus item yang cocok. Jika nilai tidak ditemukan, statemen tidak melakukan apapun:

intList.Remove(30)

Metode RemoveAt menghapus sebuah item pada posisi indeks yang diberikan:

intList.RemoveAt(0)

Metode Sort mengurutkan elemen-elemen dengan tatanan menaik:

intList.Sort()

Metode ToArray menghasilkan sebuah array yang memuat item-item list:

intList.ToArray()

Kelas List memuat banyak metode lain, yang dapat Anda baca pada dokumentasi MSDN online.


Pengurutan dengan Komparator
Kadangkala, Anda ingin mengurutkan sebuah List dengan cara yang tidak standar, seperti pengurutan dengan tatanan menurun. Atau, Anda ingin mengururkan properti lain selain yang digunakan oleh metode CompareTo. Untuk melakukannya, Anda perlu mendefinisikan sebuah metode dengan nama komparator, yang membandingkan elemen-elemen pada kedua list berdasarkan apa yang Anda butuhkan. Metode tersebut harus mengikut bentuk umum berikut:

Public Function NamaMetode(ByVal nil1 As Tipe, ByVal nil2 As Tipe) As Integer

Anda dapat menggunakan sembarang pengenal yang Anda suka untuk NamaMetode, nil1, dan nil2. Dua parameter tersebut merepresentasikan pasangan-pasangan nilai yang akan dibandingkan selama proses pengurutan. Tipe pada bentuk umum ini harus cocok dengan tipe objek di dalam List.

Fungsi-fungsi pengurutan selalu melakukan perbandingan antara pasangan-pasangan atau item-item. Komparator itu sendiri tidak mengurutkan list, karena Anda masih perlu memanggil metode Sort dari kelas List. Anda hanya perlu memberitahu metode Sort bagaimana item-item list dibandingkan.

Contoh Komparator Siswa
Dimisalkan bahwa Anda ingin mengurutkan sebuah list yang memuat objek-objek Siswa. Anda mengasumsikan bahwa kelas Siswa telah memuat sebuah metode CompareTo yang membandingkan objek-objek Siswa berdasarkan nomor ID. Anda sekarang bisa menciptakan list yang memuat objek-objek Siswa dan memanggil metode Sort:

Dim siswaList As New List(Of Siswa)
siswaList.Add(New Siswa(1234, “Jonas”));
siswaList.Add(New Siswa(4023, “Bakri”));
siswaList.Add(New Siswa(5612, “Gonzalez”));
siswaList.Add(New Siswa(1001, “Chong”));
siswaList.Sort()

List sekarang diurutkan dengan tatanan menaik berdasarkan nomor ID:

1001 Chong
1234 Jonas
4023 Bakri
5612 Gonzalez

Tetapi, jika Anda juga ingin mengurutkan list dengan tatanan menaik berdasarkan nama belakangnya, Anda perlu lebih dahulu menciptakan sebuah komparator yang membandingkan properti NamaBelakang dari objek-objek:

Public Function BandingkanNama(ByVal X As Siswa, ByVal Y As Siswa) As Integer
   Return X.NamaBelakang.CompareTo(Y. NamaBelakang)
End Function

Kemudian Anda akan mengurutkan list dengan melewatkan alamat dari komparator kepada metode Sort:

siswaList.Sort(AddressOf BandingkanNama)

Setelah pengurutan, list yang memuat siswa-siswa akan diurutkan secara menaik berdasarkan nama belakangnya:

4023 Bakri
1001 Chong
5612 Gonzalez
1234 Jonas

Dictionary(Of TipeKunci, TipeNilai)
Kelas Dictionary(Of TipeKunci, TipeNilai) memetakan suatu himpunan kunci dengan sebuah himpunan nilai. Dengan kata lain, setiap kunci di dalam kamus memiliki satu nilai yang berkaitan dengan kunci itu. Kunci-kunci harus unik, tetapi nilai-nilai boleh tidak unik (boleh duplikat). Sebuah Dictionary dioptimasi untuk pencarian terhadap himpunan kunci yang besar. Jika Anda memiliki 20 juta item di dalam sebuah Dictionary, misalnya, kunci dari satu item akan dicari dengan sesaat.

Adalah penting untuk memilih properti yang tepat pada kelas Anda untuk digunakan sebagai kunci Dictionary. Anda perlu mencari sebuah properti dengan nilai unik untuk setiap item yang Anda sisipkan di dalam Dictionary. Jika Anda menyisipkan pekerja-pekerja, misalnya, properti ID dari kelas Pekerja mungkin merupakan pilihan yang baik untuk dijadikan kunci. Di sisi lain, properti NamaBelakang bukanlah pilihan kunci yang baik karena dua pekerja bisa saja memiliki nama belakang (marga) yang sama.

Kelas-kelas dari kunci-kunci kamus harus mengimplementasikan antarmuka IComparable, dan mereka harus mendefinisikan-ulang metode Equals. Oleh karena itu, adalah sangat mudah untuk menggunakan tipe data standar .NET sebagai sebuah kunci Dictionary. Pilihan yang umum adalah Integer dan String. Nilai-nilai terkait dengan kunci dapat bertipe data apa saja, tidak ada pembatasan spesial.

Menciptakan Sebuah Dictionary
Ketika Anda mendeklarasikan sebuah objek Dictionary, Anda perlu menyediakan tipe-tipe data untuk pasangan kunci dan nilai. Bentuk umumnya adalah berikut:

Dim namaVar As New Dictionary(Of tipekunci, tipenilai)

Sebagai contoh, kode berikut mendeklarasikan sebuah Dictionary dengan nama gaji, menggunakan Integer sebagai kunci dan Decimal sebagai nilai yang berkaitan dengan kunci:

Dim gaji As New Dictionary(Of Integer, Decimal)

Menambahkan Entri ke dalam Sebuah Dictionary
Metode Add menambahkan sepasang kunci/nilai ke dalam sebuah Dictionary. Kode berikut, misalnya, menambahkan beberapa ID pekerja dan nilai-nilai gaji ke dalam Dictionary dengan nama gaji:

gaji.Add(3001, 50000D)
gaji.Add(2020, 45000D)
gaji.Add(3125, 64500D)
gaji.Add(2501, 32800D)

Ketika menyisipkan pasangan-pasangan kunci/nilai, tipe datanya harus sesuai dengan tipe-tipe data yang digunakan saat mendeklarasikan Dictionary. Inilah mengapa Anda mengatakan Dictionary sebagai koleksi bertipe data kuat. Statemen berikut adalah statemen yang salah, karena ia mencoba menyisipkan sebuah kunci string dan sebuah gaji bertipe Double:

gaji.Add(“1002”, 34000.2)

Di sisi lain, Anda dapat melewatkan sebuah integer sebagai argumen kedua karena integer secara otomatis dikonversi menjadi Decimal:

Dim N As Integer = 35000
gaji.Add(“1002”, N)

Jadi, lebih tepatnya, tipe-tipe argumen harus kompatibel dengan tipe-tipe parameter dari metode Add.

Properti Count mengindikasikan banyaknya entri di dalam Dictionary. Statemen berikut menugaskan banyaknya entri kepada sebuah Label:

labelBanyak.Text = “Terdapat ” & gaji.Count & ” entri”'

Metode Clear menghapus semua entri dari sebuah Dictionary.

Menjejak Entri-Entri Dictionary
Setiap entri di dalam sebuah Dictionary merupakan sebuah objek KeyValueObject, yang memuat dua properti: Key dan Value. Ketika Anda mendeklarasikan sebuah KeyValuePair, Anda perlu spesifik dalam menyebutkan tipe data dari kunci dan nilai. Berikut adalah bagaimana Anda mendeklarasikannya untuk Dictionary dengan nama gaji:

Dim entri As KeyValuePair(Of Integer, Decimal)

Kemudian, Anda dapat menggunakan variabel entri ketika mengkode statemen For Each. Entri itu memuat kunci dan nilai dari tiap entri Dictionary. Kode berikut menambahkan beberapa entri ke dalam kamus gaji dan kemudian menyalin entri-entri tersebut ke dalam sebuah ListBox:

gaji.Add(3001, 50000D)
gaji.Add(2020, 45000D)
gaji.Add(3125, 64500D)
gaji.Add(2501, 32800D)

For Each entry In gaji
    kotakList.Items.Add(entri.Key & “-->” & entri.Value)
Next

Loop tersebut menghasilkan keluaran berikut:

3001-->50000
2020-->45000
3125-->64500
2501-->32800


Mencari, Memodifikasi, dan Menghapus Entri
Anda tidak dapat menggunakan indeks integer untuk mengakses posisi tertentu di dalam sebuah kamus. Untuk mencari entri Dictionary, Anda harus melewatkan kunci yang ingin dicari kepada properti Item. Statemen berikut menghasilkan 45000, gaji dari pekerja dengan nomor ID 2020:

Dim pendapatan As Decimal = gaji.Item(2020)

Jika Anda mencoba membaca nilai yang berkaitan dengan kunci yang tidak ada, maka properti Item akan melemparkan eksepsi KeyNotFoundException.

Jika Anda menugaskan sebuah nilai kepada properti Item dan mereferensi sebuah kunci yang ada, maka Dictionary akan mengganti nilai yang berkaitan dengan kunci tersebut. Sebagai contoh, statemen berikut mengganti gaji dari pekerja dengan ID 3001:

gaji.Item(3001) = 62000D

Jika Anda menugaskan sebuah nilai kepada properti Item dan mereferensi sebuah kunci yang tidak ada di dalam Dictionary, maka sebuah entri baru akan diciptakan dan disisipkan. Statemen berikut menyisipkan sebuah entri baru ke dalam Dictionary, dengan mengasumsikan bahwa kunci 2025 tidak ada:

gaji.Item(2025) = 72000D

Metode Remove menghapus entri dengan kunci cocok dengan parameter masukan metode. Bentuk umumnya adalah:

namaKamus.Remove(kunci) As Boolean

Jika kunci ditemukan dan item dihapus, maka Remove akan menghasilkan True. Sebaliknya, Remove menghasilkan False. Sebagai contoh, statemen berikut menghapus entri dengan kunci 3125:

gaji.Remove(3125)


Metode Ekstensi
Metode ekstensi adalah suatu fitur di dalam NET yang dapat dipakai developer menambahkan metode baru pada kelas yang telah ada. Kelas Dictionary memiliki sejumlah banyak metode yang berkaitan dengan koleksi kunci dan nilanya. Berikut adalah beberapa di antaranya yang dicantumkan pada Tabel 3.4:

Dim rerata As Decimal = gaji.Values.Average()
Dim jum as Decimal = gaji.Values.Sum()
Dim minNil As Decimal = gaji.Values.Min()

Tabel 3.4 Metode-metode ekstensi di dalam Dictionary
Metode Ekstensi
Penjelasan
Values.Average
Values.Sum
Values.ToArray
Values.Max
Values.Min
Keys.Max
Keys.Min
Menghasilkan rerata dari nilai-nilai.
Menghasilkan penjumlahan atas nilai-nilai.
Menghasilkan sebuah array yang memuat nilai-nilai.
Menghasilkan nilai terbesar.
Menghasilkan nilai terkecil.
Menghasilkan kunci terbesar.
Menghasilkan kunci terkecil.

Kelas SortedDictionary
SortedDictionary adalah sebuah kamus yang mempertahankan kunci-kuncinya dengan urutan spesifik. Berikut adalah contohnya:

Dim gajiTerurut As New SortedDictionary(Of Integer, Decimal)

Semua metode dan properti yang telah didiskusikan untuk kelas Dictionary berlaku juga untuk kelas SortedDictionary.

Anda dapat melewatkan sebuah objek Dictionary yang telah ada kepada konstruktor dari sebuah objek SortedDictionary, sepanjang tipe data dari kunci dan nilainya sama. Sebagai contoh, statemen berikut membuat salinan dari kamus gaji ketika menciptakan gajiTerurut:

Dim gajiTerurut As New SortedDictionary(Of Integer, Decimal)
(gaji)


  
Tutorial 3.3: Menciptakan Sebuah Konkordansi Teks
Pada tutorial ini, Anda akan menciptakan sebuah aplikasi yang membangun konkordansi, yaitu sebuah katalog kata yang ditemukan pada sebuah dokumen. File masukan berupa sebuah file teks yang memuat kata-kata yang dipisahkan dengan spasi. Himpunan kata akan disimpan sebagai koleksi kunci di dalam sebuah objek Dictionary, dan tiap nilai yang berkaitan dengan kunci berupa sebuah List(Of Integer) yang memuat nomor-nomor baris dimana kata ditemukan di dalam file masukan. Dictionary akan dideklarasikan seperti ini:

Private kamusKata As New Dictionary(Of String, List(Of Integer))

Ketika aplikasi dijalankan, user akan memilih perintah Buka dari menu File, seperti ditunjukkan pada Gambar 3.9. Sebuah kontrol OpenFileDialog akan ditampilkan dan user akan memilih file masukan. File dibaca ke dalam sebuah list string, dan setiap kata dari file disisipkan ke dalam kamus.


Gambar 3.9 Saat aplikasi dijalankan, user memilih file masukan


Pada Gambar 3.10, aplikasi sekarang telah siap untuk digunakan. User dapat mengetikkan satu kata dan mengklik tombol Cari untuk melihat semua baris dari file yang memuat kata tersebut (Gambar 3.11). File yang digunakan pada kasus ini adalah novel Moby Dick karya Herman Melville.


Gambar 3.10 File masukan dimuat dan siap untuk digunakan

Jika user mengklik tombol Semua, keseluruhan kata di dalam kamus akan ditampilkan pada sebuah kotak list kolom-jamak (Gambar 3.12).

Sebelum menciptakan aplikasi, Anda perlu mempelajari kontrol OpenFileDialog.

Kontrol OpenFileDialog
Kontrol OpenFileDialog dapat dipakai user untuk memilih sebuah file pada jendela Windows standar. Ia memiliki properti InitialDirectory agar dialog dapat menuju ke direktori tertentu ketia ia dibuka. Diasumsikan bahwa kontrol itu dinamai dengan ofdBukaFile. Statemen berikut menugaskan kepadanya nilai direktori terkini dari aplikasi, yang dihasilkan oleh metode GetCurrentDirectory:

ofdBukaFile.InitialDirectory = Directory.GetCurrentDirectory()

Selain itu, Anda dapat meminta dialog untuk hanya menampilkan tipe file tertentu dengan menetapkan properti Filter dengan deskripsi tertentu, dipisahkan dengan batang vertikal dari nama wildcard (*.txt):

ofdBukaFile.Filter = “File Teks|*.txt”

Gambar 3.11 Menampilkan baris-baris yang memuat kata whale


Gambar 3.12 Menampilkan isi keseluruhan dari kamus


Metode ShowDialog menampilkan jendela dialog. User dapat mengklik tombol Open atau Cancel untuk menutup jendela. Metode ini menghasilkan sebuah nilai DialogResult yang dapat Anda pakai untuk mengetahui tombol mana yang diklik:

Dim hasil As DialogResult = ofdBukaFile.ShowDialog()

Statemen If dapat dipakai untuk memeriksa apakah tombol Open telah diklik (dengan nilai DialogResult.OK):

If hasil = DialogResult.OK Then

Jika file telah dipilih, properti FileName akan memuat path utuh dari file.

Kontrol OpenFileDialog memiliki metode OpenFile yang membuka file yang dipilih oleh user dan menghasilkan sebuah objek System.IO.Stream. Anda dapat melewatkan objek itu kepada konstruktor kelas StreamReader, sehingga aplikasi dapat menggunakan variabel infile untuk membaca baris-baris data dari file.

Dim infile As StreamReader = New StreamReader(ofdBukaFile.OpenFile())

Memfilter String
Ketika membaca kata-kata dari file masukan pada tutorial ini, Anda akan menghapus semua tanda baca seperti koma dan titik. Anda dapat mendefinisikan sebuah string yang memuat sejumlah karakter tanda baca dan mengkonversinya menjadi sebuah array karakter:

Dim buangKarakter As Char() = ("?':;.,!""").ToCharArray()

Selanjutnya, ketika Anda membaca sebuah kata dari file, Anda dapat memanggil metode TrimEnd, melewatkannya array karakter yang memuat sejumlah karakter tanda baca tersebut:

kata = kata.TrimEnd(buangKarakter)

Jadi, sebuah kata seperti “Street;” akan dikonversi menjadi “Street”. Anda dapat pula mengkonversi kata masukan menjadi huruf kecil, yang membuatnya lebih mudah untuk mencari kecocokan kata:

kata = kata.ToLower()

Ketika memeriksa sebuah kata, Anda ingin mengetahui apakah karakter pertama adalah sebuah huruf atau bukan. Kelas Char memiliki metode untuk melakukannya yang menghasilkan nilai True atau False:

If Char.IsLetter(kata(0)) Then ...

Langkah-Langkah Tutorial
Langkah 1: Ciptakanlah sebuah aplikasi baru dengan nama Pencarian Teks.

Langkah 2: Salin file dengan nama mobydick.txt ke dalam folder projek Anda.

Langkah 3: Tambahkan kontrol-kontrol seperti dicantumkan pada Tabel 3.5 pada form. Lihat kembali Gambar 3.9 untuk lokasi dari tiap kontrol. Kontrol DropDownButton pada toolstrip memuat menu File dengan dua sub item: Buka dan Keluar. Toolstrip juga memuat beberapa separator.

Tabel 3.5 Kontrol-kontrol pada aplikasi Pencarian Teks
Tipe Kontrol
Nama Kontrol
Properti
Form
ToolStrip
ListBox
ToolStripLabel
ToolStripTextBox
ToolStripDropDownButton
ToolStripMenuItem
ToolStripMenuItem
ToolStripButton
ToolStripButton
OpenFileDialog


kotakList
labelNamaFile
teksCariKata

mnuFileBuka
mnuFileKeluar
tombolCari
tombolSemua
ofdBukaFile
Text: Pencarian Teks

ColumnWidth: 100
Text: (Tidak ada file)


Text: Buka
Text: Keluar
Text: Cari
Text: Semua

Langkah 4: Buka jendela Code dari form startup dan tambahkan statemen Imports di atas kelas sebagai berikut:

Imports System.IO

Langkah 5: Di dalam kelas, sisipkan deklarasi-deklarasi berikut:

Private infile As StreamReader
Private kamusKata As New Dictionary(Of String, List(Of Integer))
Private teksMentah As New List(Of String)

Variabel teksMentah memuat semua baris masukan dari file, sehingga Anda dapat menampilkan baris-baris ini pada kotak list ketika user melakukan pencarian kata.

Langkah 7: Tambahkan fungsi BukaFileMasukan, yang menghasilkan True jika sebuah file diseleksi oleh user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Private Function BukaFileMasukan() As Boolean
    'menampilkan kontrol OpenFileDialoh dan membiarkan user
    'memilih file masukan
    With ofdBukaFile
        .InitialDirectory = Directory.GetCurrentDirectory()
        .FileName = "*.txt"
        Dim hasil As DialogResult = .ShowDialog()
        If hasil = DialogResult.OK Then
            infile = New StreamReader(.OpenFile())
            labelNamaFile.Text = "Nama File: " &
              Path.GetFileName(.FileName)
            Return True
        Else
            Return False
        End If
    End With
End Function

Baris 10 menyalin nama file dari kontrol OpenFileDialog ke dalam sebuah label pada toolstrip. Pemanggilan terhadap Path.GetFileName menghasilkan nama file setelah membuang semua path direktori.

Langkah 7: Selanjutnya, tambahkan event handler Click untuk perintah menu File | Buka:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Private Sub mnuFileBuka_Click(…) Handles mnuFileBuka.Click
    'user mengklik item menu File | Buka
    If Not BukaFileMasukan() Then Return

    'membaca tiap baris dan menyisipkan tiap kata ke dalam kamus
    'Untuk setiap kata yang ada, tambahkan nomor baris
    'pada list untuk entri kata tersebut
    Dim nomorBaris As Integer = 0
    Dim buangKarakter As Char() = ("?':;.,!""").ToCharArray()

    Do While Not infile.EndOfStream()
        Dim temp As String = infile.ReadLine()
        If temp.Trim().Length = 0 Then Continue Do

        teksMentah.Add(temp)
        Dim kataArr() As String = temp.Split(" "c)

        For Each kata As String In kataArr
            kata = kata.TrimEnd(buangKarakter).ToLower()
            If kata.Length > 0 AndAlso Char.IsLetter(kata(0)) Then
                If Not kamusKata.ContainsKey(kata) Then
                    kamusKata.Add(kata, New List(Of Integer))
                End If
                kamusKata(kata).Add(nomorBaris)
            End If
        Next
        nomorBaris += 1
    Loop
End Sub

Ini merupakan metode yang panjang, jadi Anda perlu hati-hati. Baris 3 memanggil OpenInputFile, dan keluar jika user membatalkan dialog. Baris 8 menciptakan sebuah variabel dengan nama nomorBaris, yang akan menjejak baris yang dibaca paling terakhir dari file. Baris 11 mengulangi loop sampai akhir file. Baris 12 membaca sebaris data dari file, dan baris 15 menambahkan baris tersebut pada list teksMentah yang telah dideklarasikan sebelumnya. Baris 13 melompati sisa loop jika sebaris kosong ditemukan dan kembali lagi ke baris 11. Baris 16 memecah baris masukan menjadi sebuah array yang memuat kata-kata.

Baris 18 memulai sebuah loop baru dengan pekerjaan untuk mengambil setiap kata di dalam array, memotongnya dan mengkonversinya menjadi huruf kecil (baris 19), dan memastikan bahwa ia tidak kosong dan bahwa ia diawali dengan huruf (baris 20). Kemudian pada baris 21, Anda memeriksa apakah kata telah ada di dalam kamus. Jika tidak, Anda menambahkan kata itu ke dalam kamus (baris 22) dan memberikannya sebuah nomor baris kosong. Pada baris 24, Anda menambahkan nomor baris terkini pada list yang berkaitan dengan kata terkini. Baris 27 menginkremen nomor baris dan loop kembali membaca baris lain dari file (baris 12).

Langkah 8: Tambahkan sebuah event handler Click untuk tombol Semua, yang menampilkan semua kata di dalam kamus.

1
2
3
4
5
6
7
8
Private Sub tombolSemua_Click(…) Handles tombolSemua.Click
    kotakList.MultiColumn = True
    kotakList.Items.Clear()
    For Each entri As KeyValuePair(Of String,
      List(Of Integer)) In kamusKata
        kotakList.Items.Add(entri.Key)
    Next
End Sub

Perhatikan bagaimana kode tersebut menetapkan properti MultiColumn pada kotak list untuk menampilkan sebanyak mungkin kata pada saat yang bersamaan.

Langkah 9: Ciptakanlah handler Click untuk tombol Cari. Pekerjaannya adalah mencari kata di dalam kamus dan menampilkan semua baris yang cocok dari list teksMentah.

1
2
3
4
5
6
7
8
9
10
11
12
13
Private Sub tombolCari_Click(…) Handles tombolCari.Click
    kotakList.MultiColumn = False
    kotakList.Items.Clear()
    If kamusKata.ContainsKey(teksCariKata.Text) Then
        For Each nomorBaris As Integer In kamusKata(
        teksCariKata.Text)
            kotakList.Items.Add(nomorBaris & ":" & vbTab &
             teksMentah(nomorBaris))
        Next
    Else
        kotakList.Items.Add("(kata tidak ditemukan)")
    End If
End Sub

Baris 4 memanggil metode ContainsKey untuk mencaritahu apakah kata (pada teksCariKata.Text) ada di dalam kamus atau tidak. Tipe pencarian ini dieksekusi sangat cepat. Jika kata ditemukan, maka ekspresi berikut menghasilkan sebuah objek List(Of Integer) yang memuat nomor-nomor baris diman kata itu ditemukan pada file masukan:

kamusKata(teksCariKata.Text)

Baris 5 menjelajak list yang memuat nomor-nomor baris. Baris 7 menggunakan setiap nomor baris sebagai indeks ke dalam objek list teksMentah, dan menyisipkan baris teks ke dalam kotak list. Terakhir, jika kata yang dimasukkan user tidak ditemukan, baris 11 akan menampilkan pesan kegagalan pada kotak list.

Langkah 10: Terakhir, sisipkan event handler Click untuk item menu File | Keluar.

Private Sub mnuFileKeluar_Click(…) Handles mnuFileKeluar.Click
    Me.Close()
End Sub

Langkah 11: Simpan projek dan jalankan aplikasi. Buka file mobydick.txt dari direktori projek. Klik tombol Semua untuk menampilkan semua kata yang ditemukan di dalam file.

Langkah 12: Masukkan sebuah kata ke dalam kotak teks yang ingin Anda cari, dan klik tombol Cari. Anda akan melihat sejumlah baris dari file yang memuat kata itu.


3.4 LINQ (Language Integrated Query)
LINQ (Language Integrated Query) adalah sebuah bahasa query yang dibangun ke dalam .NET yang dapat dipakai untuk menampilkan informasi dari sejumlah tipe berbeda dari sumber data. Sebagai contoh, LINQ dapat melakukan query terhadap koleksi yang memuat objek-objek (array, List, ArrayList) di dalam memori, database, file XML, Excel, dan lainnya.

Sekelompok orang cerdas di Microsoft memiliki ide cemerlang: Jika SQL merupakan bahasa yang tanggun untuk pencarian (query) dalam database, mengapa tidak menemukan jenis bahasa yang sama di dalam .NET yang dapat melakukan query terhadap sejumlah tipe data, bukan hanya database? Dan demikianlah, LINQ ditemukan. Pada bab ini, Anda akan dikenalkan tentang tipe sederhana dari LINQ yang dikenal dengan LINQ untuk objek.

Query LINQ paling sederhana mencakup empat klausa: From, Where, Select, dan Order By:
·         From: Mengidentifikasi sumber data, yang dapat berupa objek seperti array atau List.
·         Where (opsional): Memuat sebuah ekspresi Boolean yang menyeleksi nilai-nilai mana yang akan disalindari sumber data.
·         Select: Mengidentifikasi nama dari bidang (bidang-bidang) yang akan dihasilkan oleh query.
·         Order By (opsional): Mengindikasikan bagaimana hasil query diurutkan.


Contoh Array
Anda akan mempelajari bagaimana menggunakan LINQ untuk mengquery sebuah array yang memuat sejumlah integer. Perhatikan deklarasi array berikut:

Dim intNilai() As Integer = {4, 104, 2, 102, 1, 101, 3, 103}

Statemen LINQ berikut menghasilkan semua nilai array yang lebih besar dari 100:

Dim query = From item In intNilai
Where item > 100
Select item

Lihat statemen tersebut lebih detil. Pertama, perhatikan bahwa statemen tersebut diawali dengan Dim query. Anda sedang mendeklarasikan sebuah objek dengan nama query yang mendefinisikan sebuah query LINQ, tetapi Anda belum menetapkan sebuah tipe data. Visual Basic secara otomatis menentukan tipe data untuk objek, suatu teknik yang dikenal dengan inferensi tipe.

Di sisi kanan dari operator = adalah definisi query, yang memeriksa setiap item di dalam array intNilai untuk melihat apakah nilainya lebih besar dari 100, dan jika ya, klausa Select memilih nilai tersebut.

From item In intNilai
Where item > 100
Select item

Setelah query didefinisikan, Anda dapat menggunakannya dengan pelbagai cara. Anda dapat menjelajahnya, Anda dapat membangun query lain dari query tersebut, atau Anda dapat melewatkan query ke metode lain.

Sebagai contoh, segmen kode berikut menjelajah query dan menambahkan tiap nilainya pada sebuah kotak list dengan nama listHasil:

For Each intNil As Integer In query
    labelHasil.Items.Add(intNil)
Next

Karena array intNilai memuat {4, 104, 2, 102, 1, 101, 3, 103}, maka query akan menampilkan nilai 104, 102, 101, dan 103 pada kotak list, dengan urutan tersebut.

Untuk mengurutkan hasil dari query LINQ dengan tatanan menaik, Anda dapat menggunakan operator Order By, seperti ditunjukkan di sini:

Dim query = From item In intNilai
Where item > 100
Select item
Order By item

LINQ menggunakan operator seperti Where, Select, dan Order By, yang sama dengan operator pada bahasa query database SQL. Operator-operator tersebut merupakan bagian dari Visual Basic dan dapat diperiksa hasilnya oleh kompiler sebelum aplikasi dijalankan. Ini akan mempermudah  untuk mengetahui bila Anda telah melakukan kesalahan.


Contoh: Menyeleksi Integer-Integer Genap dari Array
Pada contoh ini, Anda melakukan query terhadap sebuah array yang memuat sejumlah integer, untuk mencari nilai-nilai genap (yang habis dibagi oleh 2). Selain itu, Anda akan mengurutkannya dengan tatanan menaik:

Dim angka() As Integer = {4, 3, 2, 1, 6, 9, 7}
Dim queryGenap = From nil In angka
Where (nil Mod 2 = 0)
Order By nil
Select nil

Ekspresi nil Mod 2 menghasilkan sisa setelah pembagian nil dengan 2. Jika sisanya nol, nilai tersebut pasti genap. Nilai-nilai yang dihasilkan oleh queryGenap adalah {2, 4, 6}.

Anda dapat memodifikasi sebuah query setelah ia diciptakan. Sebagai contoh, statemen berikut membalik urutan dari nilai-nilai yang dihasilkan oleh queryGenap:

queryGenap = queryGenap.Reverse()

Apa tipe dari queryGenap? Ia didefinisikan sebagai antarmuka bertipe kuat dengan nama IOrderedEnumerable(Of Integer). Hal penting di sini adalah bahwa elemen-elemen yang dihasilkan oleh query ini “mengetahui” bahwa ia adalah integer.

Membangun Query dar Query yang telah Ada
queryGenap menghasilkan nilai-nilai genap {2, 4, 6). Anda dapat membangun sebuah query kedua yang lebih lanjut membatasi nilai-nilai yang dihasilkan oleh queryGenap. Query dengan nama genapBesar berikut menghasilkan satu nilai 6:

Dim genapBesar = From nil in queryGenap
Where nil > 4
Select nil

Properti dan Metode Ekstensi
Metode ekstensi adalah sebuah metode yang menghasilkan sebuah versi termodifikasi dari keluaran dari sebuah query LINQ. Metode ekstensi semacam itu adalah Count:

queryGenap.Count()

Adalah penting untuk menyadari bahwa queryGenap tidak memuat data aktual. Ia adalah sebuah variabel yang memuat sebuah query. Anda dapat memodifikasi query, melewatkan variabel sebagai parameter, atau menugaskannya kepada variabel lain. LINQ menggunakan eksekusi deferensi, yang berarti bahwa sebuah query LINQ tidak dieksekusi sampai Anda menggunakannya. Hal ini terjadi ketika Anda mengisi sebuah kotak list dengan nilai-nilai dari query atau menggunakan item-item dengan cara lain.

Pada kode berikut, Anda menyalin sejumlah nilai keluaran yang dihasilkan oleh queryGenap ke sebuah ListBox dan kemudian menampilkan nilai rerata dari integer-integer yang dihasilkan oleh queryGenap:

For Each angka In queryGenap
    kotakList.Items.Add(angka.ToString())
Next

'menampilkan nilai rerata dari queryGenap
labelRerata.Text = “Rerata = “ & queryGenap.Average()

Melakukan Query Terhadap Sebuah List yang Memuat Objek-Objek
LINQ mempermudah untuk melakukan query terhadap list dan kamus yang memuat sejumlah objek. Khususnya, Anda dapat mengakses properti-properti objek berdasarkan nama. Untuk melihat bagaimana hal ini dilakukan, Anda akan menciptakan sebuah List(Of Siswa) dan merancang query-query LINQ yang diterapkan pada list tersebut. Anda akan mengasumsikan bahwa kelas Siswa telah didefinisikan, dan ia memiliki sebuah konstruktor dengan parameter-parameter:

Public Class Siswa
   Public Property Id As String
   Public Property NamaBelakang As String
   Public Property Status As Integer ‘nilai: 1,2,3,4
   Public Property Ipk As Double ‘indeks prestasi kumulatif
   Public Property Jurusan As String
   ‘dan lainnya
End Class

Anda dapat mengisi sebuah List dengan objek-objek Siswa, sebagai berikut:

Dim daftarSiswa As New List(Of Siswa)
With daftarSiswa
    .Add(New Siswa("1241", "Kristof", 1, 3.2, "BIO"))
    .Add(New Siswa("1641", "Bakri", 2, 3.9, "ENG"))
    .Add(New Siswa("1001", "Charles", 1, 2.6, "BIO"))
    .Add(New Siswa("2205", "Sartono", 2, 3.1, "MTH"))
    .Add(New Siswa("1961", "David", 2, 2.2, "ENG"))
    .Add(New Siswa("2210", "Vivian", 3, 2.4, "BIO"))
    .Add(New Siswa("1975", "Rico", 3, 4.0, "ENG"))
End With

Query LINQ berikut menyeleksi semua siswa dari daftarSiswa dan mengurutkan hasilnya secara menaik berdasarkan properti Siswa.Id:

Dim query = From aSiswa In daftarSiswa
Select aSiswa
Order by aSiswa.Id

Query berikut menyeleksi semua siswa dari list dan mengurutkannya berdasarkan nama belakangnya:

Dim query = From aSiswa In daftarSiswa
Select aSiswa
Order by aSiswa.NamaBelakang

Anda dapat dengan mudah menugaskan keluaran query kepada sebuah kontrol DataGridView, seperti ditunjukkan pada Gambar 3.13. Anda hanya perlu mengkonversi keluaran query menjadi sebuah List dan menugaskannya kepada properti DataSource dari grid:

dgvSiswa.DataSource = query.ToList()

Jika Anda ingin menampilkan hanya beberapa properti objek, Anda dapat mencantumkannya pada klausa Select, sebagai berikut:

Dim query = From aSiswa In daftarSiswa
Select aSiswa.Jurusan, aSiswa.NamaBelakang
Order By Jurusan
dgvSiswa.DataSource = query.ToList()

Gambar 3.13 Menampilkan sebuah query LINQ pada sebuah kontrol DataGridView

Gambar 3.14 menampilkan sebuah query LINQ pada sebuah kontrol DataGridView, dimana pengurutannya dilakukan berdasarkan nama belakang.


Gambar 3.14 Menampilkan sebuah query LINQ pada sebuah kontrol DataGridView, dimana pengurutannya didasarkan pada properti NamaBelakang


Memfilter Baris
Operator Where pada sebuah query LINQ menyediakan pemilteran, atau penyeleksian baris-baris dari sumber data. Anda dapat mengkombinasikan properti-properti objek, operator-operator perbandingan, pemanggilan-pemanggilan metode, dan operator-operator gabungan.

Query berikut menyeleksi hanya siswa-siwa dengan IPK lebih dari 3.0 dan mengurutkan hasilnya dengan tatanan menurun:

Dim query = From aSiswa In daftarSiswa
Select aSiswa
Where aSiswa.Ipk > 3.0
Order By aSiswa.Ipk Descending

Query berikut menyeleksi hanya siswa-siswa dengan IPK di bawah 3.2 dengan jurusan (BIO):

Dim query = From aSiswa In daftarSiswa
Select aSiswa
Where aSiswa.Ipk < 3.2 And aSiswa.Jurusan = “BIO”
Order By aSiswa.Ipk Descending

Daripada menggunakan nilai konstanta untuk perbandingan, Anda dapat menggunakan nilai pada kotak teks:

Dim query = From aSiswa In daftarSiswa
Select aSiswa
Where aSiswa.Ipk < CDbl(teksIpk.Text) And aSiswa.Jurusan = teksJurusan.Text
Order By aSiswa.Ipk Descending

Anda dapat menuliskan kode untuk menjelajah daftarSiswa dan melakukan perbandingan-perbandingan. Tetapi LINQ melakukan pekerjaan semacam itu dengan jauh lebih mudah. Pada Tutorial 3.4, Anda akan melihat sejumlah cara dalam melakukan query terhadap sejumlah siswa dan menghitung statistika pada list tersebut.


Tutorial 3.4: Melakukan query LINQ pada sebuah list
Pada tutorial ini, Anda akan menciptakan sebuah aplikasi yang menggunakan query LINQ untuk menampilkan, mengurutkan, memfilter, dan menghitung statistika pada sebuah list yang memuat sejumlah siswa. Form startup memiliki sebuah menu dengan seleksi-seleksi sehingga user dapat memilih pengurutan dan filter yang berbeda. Hasil dari query akan ditampilkan pada sebuah kontrol DataGridView. Gambar 3.15, misalnya, menunjukkan keluaran dari sebuah query LINQ yang mengurutkan siswa berdasarkan nama belakangnya dengan tatanan menurun.

Gambar 3.15 Mengurutkan siswa-siswa berdasarkan nama belakangnya dengan tatanan menurun


Form Statistika pada Gambar 3.16 menampilkan statistika yang dihimpun dari list, menggunakan query LINQ dan metode ekstensi. Ia menampilkan IPK rerata dari semua siswa, rentang nilai IPK dari terkecil sampai terbesar, dan IPK rerata dari jurusan yang dipilih oleh user dari sebuah kotak list. Kotak list itu sendiri diisi dengan sebuah query LINQ.

Gambar 3.16 Form Statistika menampilkan informasi tentang list siswa


Kelas Siswa yang digunakan pada kasus ini adalah:
Public Class Siswa
    Public Property Id As String
    Public Property NamaBelakang As String
    Public Property Status As Integer   'nilai: 1,2,3,4
    Public Property Ipk As Double       'indeks prestasi kumulatif
    Public Property Jurusan As String
    'dan lainnya

    Public Sub New(ByVal pId As String,
      Optional ByVal pNamaBelakang As String = "",
      Optional ByVal pStatus As Integer = 1,
      Optional ByVal pIpk As Double = 0.0,
      Optional ByVal pJurusan As String = "")
        Id = pId
        NamaBelakang = pNamaBelakang
        Status = pStatus
        Ipk = pIpk
        Jurusan = pJurusan
    End Sub
End Class

Langkah 1: Buka projek dengan nama Daftar Siswa.

Langkah 2: Periksa item-item menu utama:

Urutkan dengan
    ID, menaik
    Nama belakang, menurun
Pilih
    Siswa dengan IPK > 3.0
    Jurusan BIO dengan IPK < 3.2
Lihat
    Statistika

Langkah 3: Buka jendela Code dan periksa kode berikut:

Dim daftarSiswa As New List(Of Siswa)

Private Sub Form1_Load(…) Handles MyBase.Load
    With daftarSiswa
        .Add(New Siswa("1241", "Kristof", 1, 3.2, "BIO"))
        .Add(New Siswa("1641", "Bakri", 2, 3.9, "ENG"))
        .Add(New Siswa("1001", "Charles", 1, 2.6, "BIO"))
        .Add(New Siswa("2205", "Sartono", 2, 3.1, "MTH"))
        .Add(New Siswa("1961", "David", 2, 2.2, "ENG"))
        .Add(New Siswa("2210", "Vivian", 3, 2.4, "BIO"))
        .Add(New Siswa("1975", "Rico", 3, 4.0, "ENG"))
    End With
End Sub

Langkah 4: Periksa event handler Click untuk item menu Urutkan Dengan | ID, menaik:

Private Sub mnuUrutkanID_Click(…) Handles mnuUrutkanID.Click
    'mengurutkan berdasarkan ID, secara menaik
    Dim query = From aSiswa In daftarSiswa
    Select aSiswa
    Order By aSiswa.Id
    'konversi menjadi List(Of Siswa)
    dgvSiswa.DataSource = query.ToList()
End Sub

Langkah 5: Periksa event handler Click untuk item menu Urutkan Dengan | Nama Belakang, menurun:

Private Sub mnuUrutkanNamaBelakang_Click(…) Handles mnuUrutkanNamaBelakang.Click
    'mengurutkan berdasarkan nama belakang, secara menurun
    Dim query = From aSiswa In daftarSiswa
    Select aSiswa
    Order By aSiswa.NamaBelakang Descending
    dgvSiswa.DataSource = query.ToList()
End Sub

Langkah 6: Periksa event handler Click untuk item menu Pilih | Siswa dengan IPK > 3.0:

Private Sub mnuPilihSiswa_Click(…) Handles mnuPilihSiswa.Click
    'siswa-siswa dengan IPK > 3.0
    Dim query = From aSiswa In daftarSiswa
    Select aSiswa
    Where aSiswa.Ipk > 3.0
    Order By aSiswa.Ipk Descending
    dgvSiswa.DataSource = query.ToList()
End Sub

Langkah 7: Periksa event handler Click untuk item menu Pilih | Jurusan BIO IPK < 3.2:

Private Sub mnuPilihJurusan_Click(…) Handles mnuPilihJurusan.Click
    'jurusan BIO dengan IPK < 3.2
    Dim query = From aSiswa In daftarSiswa
    Select aSiswa
    Where aSiswa.Ipk < 3.2 And aSiswa.Jurusan = "BIO"
    Order By aSiswa.Ipk Descending
    dgvSiswa.DataSource = query.ToList()
End Sub

Langkah 8: Periksa event handler Click untuk item menu Lihat | Statistika:

Private Sub mnuLihatStatistika_Click(…) Handles mnuLihatStatistika.Click
    FormStatistika.DaftarSiswa = daftarSiswa
    FormStatistika.ShowDialog()
End Sub

Langkah 9: Jalankan aplikasi dan verifikasi semua query berdasarkan item-item menu. Kemudian hentikan aplikasi.

Form Statistika
Langkah 10: Buka jendela Code untuk form Statistika. Ia memuat sebuah properti yang memuat referensi ke list siswa yang telah diciptakan pada kelas Form1:

Public Class FormStatistika
   Public Property DaftarSiswa As New List(Of Siswa)

Langkah 11: Periksa event handler Form_Load, yang menghitung IPK rerata. Karena Anda hanya menginginkan nilai-nilai IPK, klausa Select secara spesifik menyebutkan aSiswa.Ipk:

Private Sub FormStatistika_Load(…) Handles MyBase.Load
    'menghitung IPK rerata
    Dim IPKQuery = From aSiswa In DaftarSiswa
    Select aSiswa.Ipk
    labelRerataIPK.Text = IPKQuery.Average().ToString("n")

Metode ekstensi dengan nama Average menghasilkan nilai rerata dari semua nilai yang ditemukan oleh IPKQuery.

Pada event handler yang sama, metode-metode ekstensi diterapkan pada objek IPKQuery untuk mendapatkan nilai terkecil (Min) dan nilai terbesar (Max):

'menghitung IPK min dan maks
labelRentangIPK.Text = IPKQuery.Min().ToString("n") &
  " - " & IPKQuery.Max().ToString("n")

Terakhir, kode ini mengisi kontrol ListBox dengan satu objek dari tiap jurusan. Ini dilakukan lebih dahulu dengan sebuah query dengan nama (jurusan) dan kemudian memanggil metode ekstensi dengan nama Distinct:

'mengisi kotak list dengan nama-nama jurusan
Dim jur = From aSiswa In DaftarSiswa
Select aSiswa.Jurusan
Order By Jurusan
kotakListJurusan.DataSource = jur.Distinct().ToList()

Langkah 12: Periksa event handler SelectedIndexChanged untuk ListBox:

Private Sub kotakListJurusan_SelectedIndexChanged(…)
   Handles kotakListJurusan.SelectedIndexChanged

Metode ini menghitung IPK reraa dari siswa-siswa yang memiliki jurusan terseleksi, dalam dua langkah: Pertama, ia menugaskan sebuah list siswa yang cocok dengan jurusan terseleksi kepada jurusanQuery.

Dim jurusanQuery = From aSiswa In DaftarSiswa
Select aSiswa
Where aSiswa.Jurusan = kotakListJurusan.SelectedItem.ToString

Kemudian, ia menggunakan jurusanQuery sebagai sumber untuk query kedua yang menyeleksi hanya properti Ipk dari tiap siswa.

Dim IPKQuery = From aSiswa In jurusanQuery
Select aSiswa.Ipk

Terakhir, ketika IPKQuery ditugaskan kepada kontrol Label, metode ekstensi Average menghitung IPK rerata.

labelRerataIPKJurusan.Text = IPKQuery.Average().ToString("n")

Melakukan Query Terhadap Dictionary
Anda dapat melakukan query LINQ pada sebuah Dictionary. Dengan menggunakan kelas Siswa yang sama seperti yang telah Anda gunakan sebelumnya, kode berikut mengisi Dictionary dengan entri-entri yang telah Anda gunakan untuk List:

Dim kolSiswa As New Dictionary(Of Integer, Siswa)

With kolSiswa
    .Add(New Siswa("1241", "Kristof", 1, 3.2, "BIO"))
    .Add(New Siswa("1641", "Bakri", 2, 3.9, "ENG"))
    .Add(New Siswa("1001", "Charles", 1, 2.6, "BIO"))
    .Add(New Siswa("2205", "Sartono", 2, 3.1, "MTH"))
    .Add(New Siswa("1961", "David", 2, 2.2, "ENG"))
    .Add(New Siswa("2210", "Vivian", 3, 2.4, "BIO"))
    .Add(New Siswa("1975", "Rico", 3, 4.0, "ENG"))
End With

Penulisan query LINQ untuk memproses Dictionary sedikit berbeda dari penulisan query untuk List. Setiap entri di dalam sebuah Dictionary adalah bertipe KeyValuePair, yang memiliki dua properti dengan nama Key dan Value. Operator Select di dalam sebuah query LINQ perlu mereferensi properti Value dari pasangan tersebut.

Query beriktu menyeleksi semua siswa dari Dictionary dan mengurutkannya berdasarkan nomor ID:

Dim query = From aSepasang In kolSiswa
Select aSepasang.Value
Order By Value.Id

Karena ekspresi aSepasang.Value menghasilkan sebuah objek Siswa, operator Order By perlu menggunakan Value.Id untuk mengindikasikan properti Siswa spesifik dalam mengurutkan hasil query.

Cara alternatif adalah dengan menjalankan query LINQ pada koleksi Values dari Dictionary, yang ia sendiri merupakan sebuah List. Contohnya diberikan berikut:

Dim query = From aSiswa In kolSiswa.Values
Select aSiswa
Order By aSiswa.Id

Kelas yang Memuat List-List
Salah satu fitur tangguh dari LINQ adalah kemampuannya untuk mengakses dan melakukan pencarian pada sebuah List yang bisa saja berada di dalam kelas lain. Dimisalkan bahwa sebuah program mendeklarasikan sebuah list yang memuat objek-objek Akun, sebagai berikut:

Dim akunList As List(Of Akun)

Setiap Akun memuat sebuah ID dan sebuah list yang memuat sejumlah saham:

Class Akun
    Public Property ID As Integer
    Public Property SahamList As List(Of Saham)
End Class

Sebuah objek Saham memuat sebuah Penjelasan dan sebuah harga:

Class Saham
    Public Property Penjelasan As String
    Public Property Harga As Double
End Class

Pertama, Anda dapat menuliskan sebuah query LINQ yang menyeleksi satu akun yang sesuai/cocok dengan nomor ID yang disimpan di dalam sebuah variabel dengan nama IDAkunCari:

Dim querySatu = From ak In akunList
Where ak.ID = IDAkunCari
Select ak


Setelah querySatu memuat objek Akun terseleksi, Anda dapat memanggil metode ekstensi ElementAt untuk menghasilkan sebuah referensi yang menunjuk ke objek Akun dan membaca list yang memuat saham-saham:

Dim sahamList As List(Of Saham) = querySatu.ElementAt(0).SahamList

Banyak programer yang menghemat kode dengan menggabungkan hal ini menjadi satu query. Perhatikan bagaimana kurung harus mengapit list pertama sebelum memanggil metode ElementAt:

sahamList = (From ak In akunList
Where ak.ID = IDAkunCari
Select ak).ElementAt(0).SahamList













No comments:

Post a Comment