Masukkan Password
13 Set in Dart | Understanding the Dart Set Class
Teks ini membahas Set pada Dart, yang merupakan salah satu collection penting selain List.
Ada beberapa istilah dalam transkrip yang salah karena hasil speech-to-text, misalnya “state” sebenarnya Set, “element at” adalah elementAt(), dan “immutable/constant set” berkaitan dengan Set yang tidak bisa dimodifikasi.
Aku akan jelaskan dari dasar sampai bagian yang lebih lanjut dengan contoh sederhana.
1. Apa itu Set?
Set adalah collection yang digunakan untuk menyimpan sekumpulan data unik.
Contoh:
Set<String> animals = {
'Cat',
'Dog',
'Tiger',
};
Secara sederhana:
Set
├── Cat
├── Dog
└── Tiger
Perbedaan utama dengan List:
List | Set |
|---|---|
| Boleh ada data duplikat | ❌ Tidak boleh duplikat |
| Memiliki index | ❌ Tidak memiliki index |
| Cocok untuk data berurutan | Cocok untuk data unik |
list[0] bisa digunakan | set[0] tidak bisa |
Contoh List:
List<int> numbers = [10, 20, 20, 30];
Hasil:
[10, 20, 20, 30]
Ada dua 20.
Sedangkan:
Set<int> numbers = {10, 20, 20, 30};
Hasilnya hanya:
{10, 20, 30}
Set otomatis menghilangkan duplikat.
2. Apa yang terjadi kalau kita memasukkan data duplikat?
Misalnya:
Set<int> numbers = {10, 20, 30};
numbers.add(20);
Apakah error?
Tidak.
Dart hanya mengabaikan data tersebut karena 20 sudah ada.
Hasil tetap:
{10, 20, 30}
Jadi:
Setmemastikan setiap elemen hanya muncul satu kali.
Ini sangat berguna kalau kita ingin menyimpan data yang harus unik.
Misalnya:
Daftar kategori
Daftar tag
Daftar ID unik
Daftar username unik
Daftar pilihan unik
3. Apakah Set memiliki index?
Tidak.
Pada List:
List<String> animals = [
'Cat',
'Dog',
'Tiger'
];
print(animals[0]);
Bisa.
Hasil:
Cat
Tetapi pada Set:
Set<String> animals = {
'Cat',
'Dog',
'Tiger'
};
Kita tidak bisa melakukan:
animals[0]
Karena Set tidak mempunyai konsep index seperti List.
Ini merupakan salah satu perbedaan paling penting.
4. Kenapa Set tidak menggunakan index?
Karena tujuan utama Set adalah menyimpan data unik, bukan menyediakan akses berdasarkan posisi.
Misalnya:
Set<String> names = {
'John',
'Alex',
'Mark'
};
Kita tidak seharusnya berpikir:
index 0 → John
index 1 → Alex
index 2 → Mark
seperti pada List.
Untuk Set, lebih tepat berpikir:
Set
├── John
├── Alex
└── Mark
5. Cara membuat Set
Ada beberapa cara.
Cara 1 — menggunakan {}
var names = <String>{};
Ini membuat Set<String> kosong.
Kemudian:
names.add('John');
names.add('Alex');
Cara 2 — menggunakan Set<T>()
Set<String> names = <String>{};
Ini adalah cara yang eksplisit.
Kita mengatakan:
Saya ingin membuat Set yang hanya berisi
String.
Cara 3 — menggunakan Set<T>.of()
Misalnya kita sudah mempunyai collection:
List<int> numbers = [10, 20, 30];
Set<int> numbersSet = Set<int>.of(numbers);
Hasil:
{10, 20, 30}
Cara 4 — menggunakan constructor Set()
Misalnya:
var numbers = <int>{};
Ini juga sering digunakan karena type inference membantu Dart mengetahui tipe datanya.
6. Hati-hati dengan {}
Ini bagian yang sangat penting.
Di Dart, {} bisa digunakan untuk membuat:
SetMap
Contoh:
var data = {};
Ini bukan Set kosong yang aman untuk diasumsikan.
Dart akan memperlakukannya sebagai Map kosong dalam konteks tersebut.
Kalau ingin memastikan itu Set:
var data = <int>{};
atau:
Set<int> data = {};
7. Kenapa Set dan Map sama-sama menggunakan {}?
Karena sintaks literalnya memang mirip.
Set:
Set<int> numbers = {10, 20, 30};
Hanya ada nilai:
10
20
30
Map:
Map<int, String> students = {
1: 'John',
2: 'Alex',
};
Ada pasangan:
key : value
Jadi:
{10, 20, 30}
→ Set
Sedangkan:
{1: 'John', 2: 'Alex'}
→ Map
Cara mudah membedakannya:
Set berisi value saja. Map berisi key dan value.
8. Set dengan data awal
Kita bisa langsung membuat Set dengan data.
Set<String> names = {
'Mark',
'Alex',
'James',
};
Kemudian:
print(names);
Hasilnya berisi ketiga nama tersebut.
9. Duplikat otomatis dihilangkan
Perhatikan:
Set<int> numbers = {
10,
20,
20,
30,
20,
};
Walaupun 20 ditulis berkali-kali, hasilnya hanya:
{10, 20, 30}
Ini adalah salah satu alasan utama menggunakan Set.
10. Set harus memiliki tipe yang sesuai
Misalnya:
Set<int> numbers = {
10,
20,
30,
};
Berarti semua elemen harus int.
Kalau kita mencoba:
numbers.add(5.5);
akan terjadi error karena 5.5 adalah double, bukan int.
Begitu juga:
numbers.add('Hello');
juga tidak diperbolehkan.
11. dynamic Set
Kita juga bisa membuat Set yang isinya bermacam-macam tipe:
Set<dynamic> data = {
'John',
10,
20.5,
true,
};
Isinya:
String
int
double
bool
Tetapi untuk aplikasi nyata, biasanya lebih baik menggunakan tipe yang spesifik jika memang memungkinkan.
Misalnya:
Set<String>
daripada:
Set<dynamic>
Karena lebih aman dan lebih mudah dipahami.
12. Membuat Set dari Set lain
Dart menyediakan beberapa constructor untuk membuat Set dari collection lain.
Yang penting dipahami:
Set<int>.from(...)
Set<int>.of(...)
Set<int>.unmodifiable(...)
13. Set.from()
Misalnya:
Set<int> set1 = {10, 20, 30};
Set<int> set2 = Set<int>.from(set1);
Sekarang set2 mempunyai data dari set1.
set1 → {10, 20, 30}
set2 → {10, 20, 30}
Catatan penting
Set.from() relatif lebih longgar dalam hal pemeriksaan tipe dibanding Set.of().
Jadi untuk kode modern yang ingin type-safe, of() sering lebih jelas.
14. Set.of()
Contoh:
Set<int> set1 = {10, 20, 30};
Set<int> set2 = Set<int>.of(set1);
Artinya:
Buat Set baru dengan tipe
intmenggunakan data dariset1.
Kalau tipe tidak sesuai, analyzer Dart bisa memberikan error lebih awal.
15. Set.unmodifiable()
Ini digunakan ketika kita ingin membuat Set yang tidak bisa dimodifikasi.
Contoh:
Set<int> numbers = Set<int>.unmodifiable({
10,
20,
30,
});
Kemudian:
numbers.add(40);
akan menghasilkan error saat dijalankan karena Set tersebut tidak dapat dimodifikasi.
Begitu juga:
numbers.remove(10);
tidak diperbolehkan.
16. Mutable vs Immutable
Ini konsep yang penting.
Mutable
Artinya data masih bisa diubah.
final numbers = <int>{10, 20, 30};
numbers.add(40);
Boleh.
Karena final di sini hanya berarti variabel numbers tidak boleh diarahkan ke object Set lain.
Object Set-nya sendiri masih bisa berubah.
Immutable / unmodifiable
Artinya isi collection tidak bisa diubah.
final numbers = Set<int>.unmodifiable({
10,
20,
30,
});
Sekarang:
numbers.add(40);
tidak boleh.
17. const Set
Ada juga:
const Set<int> numbers = {
10,
20,
30,
};
Karena const, Set tersebut merupakan constant collection dan tidak dapat dimodifikasi.
Tidak bisa:
numbers.add(40);
Tidak bisa:
numbers.remove(10);
Dan tentu saja tidak bisa mengganti variable const tersebut.
18. Bedakan final dan const
Ini sering membingungkan pemula.
final
final numbers = <int>{10, 20, 30};
numbers.add(40); // BOLEH
Variable tidak bisa diarahkan ke object baru:
numbers = {1, 2, 3}; // ERROR
Tetapi isi Set masih bisa diubah.
const
const numbers = <int>{10, 20, 30};
numbers.add(40); // ERROR
Isi collection juga tidak bisa diubah.
Jadi:
final
→ variable tidak bisa di-reassign
→ object masih bisa mutable
const
→ object bersifat constant
→ tidak bisa dimodifikasi
19. Bagaimana cara mengambil elemen Set?
Karena tidak ada index, kita tidak bisa:
animals[0]
Tetapi Dart menyediakan:
elementAt()
Misalnya:
Set<String> animals = {
'Dog',
'Cat',
'Lion',
'Monkey',
};
print(animals.elementAt(0));
Secara konsep kita mendapatkan elemen pada posisi tersebut.
Namun ada catatan penting:
Jangan memperlakukan Set seperti List.
Kalau kebutuhan utama kita adalah akses berdasarkan index, gunakan List.
20. Kenapa elementAt() bukan cara yang ideal?
Karena Set bukan collection yang dirancang untuk akses berdasarkan posisi.
Tujuan Set adalah:
"Apakah data ini ada?"
bukan:
"Apa isi index ke-3?"
Kalau kita sering membutuhkan:
data[0]
data[1]
data[2]
lebih tepat menggunakan List.
21. elementAt() juga bisa menyebabkan error
Misalnya Set hanya mempunyai tiga elemen:
Set<String> animals = {
'Dog',
'Cat',
'Lion',
};
Posisi yang tersedia secara iterasi hanya:
0
1
2
Kalau:
animals.elementAt(3);
akan menghasilkan error karena elemen tersebut tidak ada.
22. Cara melakukan loop pada Set
Ada beberapa cara.
A. for-in
Ini cara yang sangat mudah.
Set<String> animals = {
'Dog',
'Cat',
'Lion',
'Monkey',
};
for (var animal in animals) {
print(animal);
}
Konsepnya:
ambil Dog → print
ambil Cat → print
ambil Lion → print
ambil Monkey → print
23. forEach()
Kita juga bisa menggunakan:
animals.forEach((animal) {
print(animal);
});
Atau lebih singkat:
animals.forEach((animal) => print(animal));
Artinya:
Jalankan function tersebut untuk setiap elemen Set.
24. Normal for
Kita juga bisa menggunakan:
for (int i = 0; i < animals.length; i++) {
print(animals.elementAt(i));
}
Tetapi ini bukan cara yang paling direkomendasikan untuk Set.
Kenapa?
Karena Set memang tidak didesain untuk akses berdasarkan index.
Lebih baik:
for (var animal in animals) {
print(animal);
}
25. Bisa tidak mengubah nilai Set saat looping?
Nah, ini poin penting.
Misalnya:
Set<int> numbers = {10, 20, 30};
for (var number in numbers) {
number = number + 1;
}
Apakah numbers menjadi:
{11, 21, 31}
?
Tidak.
Tetap:
{10, 20, 30}
Kenapa?
Karena number hanyalah variable lokal yang menerima nilai elemen tersebut.
Kita bukan mengubah elemen di dalam Set.
26. Contoh sederhananya
Bayangkan:
for (var number in numbers)
seperti:
number ← 10
number ← 20
number ← 30
Ketika kita melakukan:
number = number + 1;
kita hanya mengubah variable number, bukan isi Set.
27. Bagaimana kalau ingin mengubah isi Set?
Karena Set tidak memiliki akses index untuk mengganti elemen, biasanya kita membuat Set baru.
Misalnya:
Set<int> numbers = {10, 20, 30};
Set<int> newNumbers = numbers
.map((number) => number + 1)
.toSet();
Hasil:
numbers → {10, 20, 30}
newNumbers → {11, 21, 31}
Perhatikan:
Kita tidak mengubah Set lama. Kita membuat Set baru.
28. Set tidak bisa mengganti elemen berdasarkan index
Pada List kita bisa:
List<int> numbers = [10, 20, 30];
numbers[2] = 100;
Hasil:
[10, 20, 100]
Pada Set tidak bisa melakukan:
numbers[2] = 100;
Karena Set tidak memiliki index seperti List.
Kalau ingin “mengganti” 30 menjadi 100, kita bisa:
Set<int> numbers = {10, 20, 30};
numbers.remove(30);
numbers.add(100);
Sekarang:
{10, 20, 100}
Tetapi secara konsep kita menghapus 30 dan menambahkan 100, bukan mengganti elemen berdasarkan index.
29. Fitur Set #1 — Collection if
Dart mendukung penggunaan if ketika membuat Set.
Contoh:
bool addExtra = true;
Set<int> numbers = {
10,
20,
if (addExtra) 30,
};
Kalau:
addExtra = true;
hasil:
{10, 20, 30}
Kalau:
addExtra = false;
hasil:
{10, 20}
Ini disebut collection-if.
30. Collection for
Kita juga bisa menggunakan for ketika membuat Set.
Contoh:
Set<int> numbers = {
10,
20,
for (int i = 1; i <= 5; i++) i,
};
Hasil:
{10, 20, 1, 2, 3, 4, 5}
Ini sangat berguna di Flutter ketika membuat widget secara dinamis.
Misalnya nanti:
children: [
for (var item in items)
Text(item),
]
Konsepnya sama.
31. Collection spread ...
Kita juga bisa mengambil isi Set lain menggunakan spread operator.
Misalnya:
Set<int> set1 = {1, 2, 3};
Set<int> set2 = {
10,
20,
...set1,
};
Hasil:
{10, 20, 1, 2, 3}
...set1 artinya:
Masukkan semua elemen
set1ke collection ini.
32. Null-aware spread ...?
Ada juga:
...?set1
Ini berguna ketika Set yang akan dimasukkan mungkin null.
Contoh:
Set<int>? numbers;
Set<int> result = {
10,
20,
...?numbers,
};
Kalau numbers == null, Dart tidak akan error karena menggunakan:
...?
Ini sangat berguna dalam kode yang menggunakan null safety.
33. Fitur #3 — elementAt()
Seperti yang sudah kita bahas:
animals.elementAt(0);
bisa digunakan untuk mendapatkan elemen berdasarkan posisi iterasi.
Tetapi jangan lupa:
Ini bukan berarti Set memiliki index seperti List.
elementAt() hanya melakukan iterasi sampai posisi yang diminta.
34. Fitur #4 — mengubah elemen saat for-in tidak mengubah Set
Misalnya:
Set<int> numbers = {10, 20, 30, 40};
for (var number in numbers) {
number += 5;
}
print(numbers);
Hasil tetap:
{10, 20, 30, 40}
Karena number hanya variable sementara.
Hal yang sama berlaku pada forEach().
35. Fitur #5 — Set adalah abstract class
Ini agak advanced, tapi bagus untuk dipahami.
Secara Dart, Set adalah sebuah abstract class/interface-like abstraction untuk kumpulan data unik.
Jadi ketika kita menulis:
Set<int> numbers = {10, 20, 30};
kita menggunakan tipe Set, tetapi object konkretnya ditangani oleh implementasi Dart.
Dalam implementasi Dart, salah satu implementasi konkretnya adalah LinkedHashSet.
Jadi sederhananya:
Set
│
│ abstraction
↓
implementasi konkret
Kita tidak perlu terlalu memikirkan detail ini ketika baru belajar Flutter.
Yang penting:
Kita menggunakan
Setsebagai tipe data, sementara Dart yang menangani implementasi konkretnya.
36. Fitur #6 — Set tidak bisa diakses seperti List
Ini sebenarnya kembali ke konsep inti Set.
Tidak bisa:
set[0]
Tidak bisa:
set[1] = 100;
Tidak bisa:
set[2] = 500;
Kalau membutuhkan operasi berdasarkan index, gunakan:
List
Kalau membutuhkan data unik, gunakan:
Set
37. Bagaimana “mengganti” elemen Set?
Misalnya:
Set<int> numbers = {
10,
20,
30,
40,
};
Kita ingin seolah-olah mengganti 30 menjadi 100.
Karena tidak ada:
numbers[2] = 100;
kita bisa membuat Set baru.
Contoh:
Set<int> modifiedNumbers = {};
int index = 2;
int newValue = 100;
int i = 0;
for (var number in numbers) {
if (i == index) {
modifiedNumbers.add(newValue);
} else {
modifiedNumbers.add(number);
}
i++;
}
print(modifiedNumbers);
Hasil secara konsep:
{10, 20, 100, 40}
Tetapi sekali lagi:
Kita sebenarnya tidak mengganti elemen dalam Set lama.
Kita membuat Set baru.
38. Tapi ada masalah penting dengan konsep “index” pada Set
Ini perlu diluruskan dari transkrip video.
Walaupun elementAt() memungkinkan kita mengambil elemen berdasarkan posisi iterasi, Set bukan collection yang sebaiknya digunakan ketika posisi/index merupakan bagian penting dari logika program.
Misalnya jangan membuat desain aplikasi seperti:
Set
↓
index 0 = user pertama
index 1 = user kedua
index 2 = user ketiga
Kalau memang posisi penting, gunakan:
List
Kalau yang penting adalah keunikan:
Set
39. Kapan sebaiknya menggunakan List?
Gunakan List kalau:
- urutan penting
- ingin mengakses berdasarkan index
- data boleh duplikat
- membutuhkan operasi seperti
list[0]
Contoh:
List<String> playlist = [
'Song A',
'Song B',
'Song A',
];
Duplikat diperbolehkan.
40. Kapan sebaiknya menggunakan Set?
Gunakan Set kalau:
- data harus unik
- tidak membutuhkan akses berdasarkan index
- ingin menghilangkan duplikat
- ingin melakukan operasi membership seperti “apakah data ini ada?”
Contoh:
Set<String> tags = {
'flutter',
'dart',
'mobile',
};
Kalau ada:
tags.add('flutter');
tidak akan membuat flutter menjadi dua kali.
41. Contoh nyata di Flutter
Misalnya aplikasi memiliki sistem tag.
User memasukkan:
Flutter
Dart
Flutter
Mobile
Dart
Kalau menggunakan List:
List<String> tags = [
'Flutter',
'Dart',
'Flutter',
'Mobile',
'Dart',
];
Hasilnya masih ada duplikat.
Kalau menggunakan Set:
Set<String> tags = {
'Flutter',
'Dart',
'Flutter',
'Mobile',
'Dart',
};
Hasil:
{Flutter, Dart, Mobile}
Ini sangat cocok untuk tag.
42. Contoh penggunaan Set untuk ID
Misalnya kita punya ID produk:
Set<int> productIds = {
101,
102,
103,
};
Kalau kita menambahkan:
productIds.add(102);
tidak akan muncul dua kali.
Ini berguna ketika kita ingin memastikan ID tidak duplikat.
43. Contoh sederhana: List → Set
Ini salah satu penggunaan Set yang sangat umum.
Misalnya:
List<int> numbers = [
10,
20,
20,
30,
30,
30,
];
Kita ingin menghilangkan duplikat:
Set<int> uniqueNumbers = numbers.toSet();
Hasil:
{10, 20, 30}
Kalau kita ingin kembali menjadi List:
List<int> result = numbers.toSet().toList();
Hasil:
[10, 20, 30]
Ini trik yang sangat berguna.
44. Perbedaan List, Set, dan Map
Sekarang kita bisa membandingkan ketiganya:
| Collection | Isi | Duplikat | Index |
|---|---|---|---|
List | Value | ✅ Boleh | ✅ Ada |
Set | Value unik | ❌ Tidak | ❌ Tidak |
Map | Key + Value | Key harus unik | ❌ Tidak seperti List |
Contoh:
List
[10, 20, 20, 30]
Set
{10, 20, 30}
Map
{
1: 'John',
2: 'Alex',
}
45. Cara paling mudah mengingat List vs Set
Bayangkan kamu memiliki daftar peserta.
List
Andi
Budi
Andi
Citra
Budi
Tidak masalah ada nama yang sama.
Set
Andi
Budi
Citra
Nama yang sama otomatis tidak disimpan dua kali.
Jadi:
List = kumpulan data berurutan.
Set = kumpulan data unik.
46. Ringkasan method penting Set
Beberapa method yang perlu kamu kenal:
Menambah
add()
addAll()
Menghapus
remove()
clear()
removeWhere()
retainWhere()
Mengecek
contains()
containsAll()
isEmpty
isNotEmpty
length
Mengubah collection
map()
where()
toList()
toSet()
Mengambil elemen
elementAt()
first
last
Dan operasi set yang sangat berguna:
union()
intersection()
difference()
47. Operasi Set yang sangat penting: union()
Misalnya:
Set<int> a = {1, 2, 3};
Set<int> b = {3, 4, 5};
Kita ingin menggabungkan keduanya:
var result = a.union(b);
Hasil:
{1, 2, 3, 4, 5}
3 tidak menjadi dua karena Set hanya menyimpan nilai unik.
48. intersection()
Digunakan untuk mencari data yang sama-sama dimiliki oleh dua Set.
Set<int> a = {1, 2, 3};
Set<int> b = {2, 3, 4};
var result = a.intersection(b);
Hasil:
{2, 3}
Karena 2 dan 3 terdapat di kedua Set.
49. difference()
Digunakan untuk mencari data yang ada di Set pertama tetapi tidak ada di Set kedua.
Set<int> a = {1, 2, 3};
Set<int> b = {2, 3, 4};
var result = a.difference(b);
Hasil:
{1}
Karena 1 hanya terdapat di a.
50. Gambaran besar Set
Kalau diringkas:
SET
│
┌──────────┴──────────┐
│ │
DATA UNIK NO INDEX
│ │
↓ ↓
duplikat hilang bukan set[0]
│
┌──────────┴─────────┐
↓ ↓
for-in forEach()
│
↓
elementAt()
Dan saat membuat Set:
Set<int> numbers = {10, 20, 30};
↓
hanya data unik
↓
{10, 20, 30}
Kalau:
numbers.add(20);
hasil tetap:
{10, 20, 30}
51. Yang paling penting kamu pahami
Kalau kamu baru belajar Dart, jangan menghafalkan semua method dulu. Kuasai konsep berikut:
① Set menyimpan data unik
{1, 2, 2, 3}
menjadi:
{1, 2, 3}
② Tidak ada akses index seperti List
set[0] // ❌
Gunakan:
set.elementAt(0)
jika memang diperlukan.
③ Set cocok untuk data yang harus unik
Contoh:
Set<String> tags;
Set<int> ids;
Set<String> categories;
④ Set bisa dibuat mutable atau unmodifiable
Mutable:
final numbers = <int>{1, 2, 3};
numbers.add(4); // boleh
Unmodifiable:
final numbers = Set<int>.unmodifiable({1, 2, 3});
numbers.add(4); // ❌
⑤ Set mendukung collection if, for, dan spread
Set<int> numbers = {
1,
2,
if (true) 3,
for (var i = 4; i <= 5; i++) i,
};
Hasil:
{1, 2, 3, 4, 5}
🧠 Inti materi dalam satu tabel
| Konsep | Contoh | Fungsi |
|---|---|---|
| Membuat Set | Set<int> x = {1, 2} | Membuat Set |
| Tambah | x.add(3) | Menambah elemen |
| Tambah banyak | x.addAll({4, 5}) | Menambah banyak elemen |
| Hapus | x.remove(2) | Menghapus elemen |
| Cek data | x.contains(3) | Mengecek apakah ada |
| Jumlah | x.length | Menghitung elemen |
| Akses posisi | x.elementAt(0) | Mengambil berdasarkan posisi iterasi |
| Loop | for (var item in x) | Iterasi |
| Gabung | x.union(y) | Menggabungkan Set |
| Irisan | x.intersection(y) | Mencari data yang sama |
| Selisih | x.difference(y) | Mencari data yang hanya ada di Set pertama |
| Ke List | x.toList() | Mengubah menjadi List |
| Unmodifiable | Set.unmodifiable(x) | Membuat Set tidak bisa diubah |
Satu kalimat untuk mengingat semuanya:
Listdigunakan ketika urutan dan index penting, sedangkanSetdigunakan ketika kita membutuhkan kumpulan data yang unik dan tidak membutuhkan akses berdasarkan index.
Dan satu hal yang sangat penting dari materi ini: jangan menganggap Set sebagai List yang otomatis menghapus duplikat. Keduanya memang sama-sama collection, tetapi tujuan desainnya berbeda. Kalau kamu membutuhkan data[index], gunakan List; kalau kamu membutuhkan keunikan data, gunakan Set.