24. Bekerja dengan slice
Kamu sudah membuat slice dengan tangan dan menelusurinya dengan
range. Pustaka standar Go juga punya package
slices, dengan fungsi untuk pekerjaan
umum: mengurutkan, membalik, mencari. Pelajari ini, dan kamu jarang
perlu menulis perulangannya sendiri.
Tambahkan "slices" ke import-mu. Package ini butuh Go
1.21 atau lebih baru, yang sudah kamu dapatkan dari Bab 06. Sebagian
besar alat di bab ini juga ada di
exercises/24/02-slice-tools.go.
Mengurutkan slice:
slices.Sort
slices.Sort menyusun ulang slice di
tempat. Fungsi ini mengubah aslinya, dan tidak mengembalikan
apa-apa:
scores := []int{30, 12, 7, 24}
slices.Sort(scores)
fmt.Println(scores) // [7 12 24 30]Teks juga diurutkan menurut abjad:
names := []string{"Cara", "Ada", "Ben"}
slices.Sort(names)
fmt.Println(names) // [Ada Ben Cara]Karena tidak mengembalikan apa-apa, tidak ada nilai yang bisa ditugaskan:
scores := []int{30, 12, 7, 24}
sorted := slices.Sort(scores)
fmt.Println(sorted)slices.Sort(scores) (no value) used as value
Untuk mempertahankan urutan aslinya, urutkan salinannya. Ini
make dan copy dari Bab 22:
scores := []int{30, 12, 7, 24}
ascending := make([]int, len(scores))
copy(ascending, scores)
slices.Sort(ascending)
fmt.Println(ascending) // [7 12 24 30]
fmt.Println(scores) // [30 12 7 24]Mengurutkan dengan caramu sendiri
Untuk dari tertinggi ke terendah, urutkan dulu, lalu balik:
scores := []int{30, 12, 7, 24}
slices.Sort(scores)
slices.Reverse(scores)
fmt.Println(scores) // [30 24 12 7]Untuk mengurutkan berdasarkan hal lain, tulis fungsi yang
membandingkan dua item dan berikan ke slices.SortFunc.
Fungsi itu mengembalikan angka negatif kalau a lebih dulu,
angka positif kalau b lebih dulu, dan 0 kalau
keduanya sama. Ini contoh mengurutkan berdasarkan panjang:
func byLength(a string, b string) int {
return len(a) - len(b)
}
func main() {
words := []string{"banana", "fig", "apple", "kiwi"}
slices.SortFunc(words, byLength)
fmt.Println(words) // [fig kiwi apple banana]
}Perhatikan bahwa byLength tidak memakai ()
di panggilan itu. Kamu menyerahkan fungsinya sendiri kepada
slices.SortFunc, yang memanggilnya sesering yang
diperlukan.
Buka exercises/24/01-sort.go. Slice berisi angka sudah
disediakan. Urutkan dari terendah ke tertinggi dan cetak, lalu urutkan
dari tertinggi ke terendah dan cetak lagi.
Membalik slice:
slices.Reverse
slices.Reverse membalik slice di tempat:
items := []string{"a", "b", "c"}
slices.Reverse(items)
fmt.Println(items) // [c b a]Untuk mendapat salinan terbalik tanpa mengubah aslinya, salin dulu:
items := []string{"a", "b", "c"}
flipped := make([]string, len(items))
copy(flipped, items)
slices.Reverse(flipped)
fmt.Println(flipped) // [c b a]
fmt.Println(items) // [a b c]Menggabungkan slice menjadi teks
strings.Join, dari package strings,
menyatukan setiap item menjadi satu string, dengan pemisah di antaranya.
Slice-nya ditulis lebih dulu, dan itemnya harus string:
fruits := []string{"apple", "banana", "cherry"}
fmt.Println(strings.Join(fruits, ", ")) // apple, banana, cherry
fmt.Println(strings.Join(fruits, " - ")) // apple - banana - cherry
fmt.Println(strings.Join(fruits, "")) // applebananacherryUntuk slice berisi angka, ubah dulu menjadi teks, dengan perulangan
dan strconv.Itoa:
scores := []int{7, 12, 24, 30}
parts := []string{}
for _, score := range scores {
parts = append(parts, strconv.Itoa(score))
}
fmt.Println(strings.Join(parts, " ")) // 7 12 24 30Memberikan angkanya langsung tidak bisa dikompilasi:
cannot use scores (variable of type []int) as []string value in argument to strings.Join
Menyalin slice: copy
copy butuh slice tujuan dengan panjang yang tepat.
make memberimu slice itu:
original := []int{1, 2, 3}
duplicate := make([]int, len(original))
copy(duplicate, original)
duplicate[0] = 99
fmt.Println(original) // [1 2 3]
fmt.Println(duplicate) // [99 2 3]Tanpa copy, menugaskan slice ke variabel lain memberimu
nama kedua untuk item yang sama, seperti yang ditunjukkan Bab 22.
copy hanya mengisi item sebanyak yang muat, jadi kalau
slice barunya lebih pendek, sisanya tidak ikut.
Mencari:
slices.Index dan slices.Contains
slices.Index memberikan posisi kecocokan pertama, atau
-1 kalau tidak ada. Ini jawaban yang sama dengan
strings.Index di Bab 14:
fruits := []string{"apple", "banana", "cherry", "banana"}
fmt.Println(slices.Index(fruits, "banana")) // 1
fmt.Println(slices.Index(fruits, "grape")) // -1slices.Contains memberikan true atau
false, kalau kamu tidak butuh posisinya:
fruits := []string{"apple", "banana", "cherry", "banana"}
if slices.Contains(fruits, "grape") {
fmt.Println("found")
} else {
fmt.Println("not found")
}Package ini tidak punya fungsi untuk menghitung kecocokan, tetapi menulisnya sendiri cukup singkat, memakai pola hitung dari Bab 20:
func countOf(items []string, value string) int {
count := 0
for _, item := range items {
if item == value {
count++
}
}
return count
}
func main() {
fruits := []string{"apple", "banana", "cherry", "banana"}
fmt.Println(countOf(fruits, "banana")) // 2
fmt.Println(countOf(fruits, "grape")) // 0
}Menghapus item berdasarkan nilai
Sekarang kamu bisa mencari item dan menghapusnya, dengan pemotongan dari Bab 22:
fruits := []string{"apple", "banana", "cherry"}
i := slices.Index(fruits, "banana")
if i != -1 {
fruits = append(fruits[:i], fruits[i+1:]...)
}
fmt.Println(fruits) // [apple cherry]
i = slices.Index(fruits, "grape")
if i != -1 {
fruits = append(fruits[:i], fruits[i+1:]...)
}
fmt.Println(fruits) // [apple cherry]if itu penting. Tanpanya, slices.Index
memberikan -1 untuk item yang tidak ada,
fruits[:i] diminta berhenti di posisi -1, dan
program crash:
panic: runtime error: slice bounds out of range [:-1]
Package ini juga punya slices.Insert, yang menambahkan
item di posisi mana pun, dan slices.Delete, yang menghapus
rentang posisi. Keduanya mengembalikan slice baru, jadi simpan hasilnya,
seperti pada append:
fruits := []string{"apple", "cherry"}
fruits = slices.Insert(fruits, 1, "banana")
fmt.Println(fruits) // [apple banana cherry]
fruits = slices.Delete(fruits, 0, 1)
fmt.Println(fruits) // [banana cherry]Membuat slice baru dengan perulangan
Untuk membuat slice baru dari slice lama, mulai dengan slice kosong
dan pakai append di dalam perulangan
range:
nums := []int{1, 2, 3, 4, 5}
doubled := []int{}
for _, n := range nums {
doubled = append(doubled, n*2)
}
fmt.Println(doubled) // [2 4 6 8 10]Tambahkan if untuk menyimpan sebagian item saja:
nums := []int{1, 2, 3, 4, 5}
evens := []int{}
for _, n := range nums {
if n%2 == 0 {
evens = append(evens, n)
}
}
fmt.Println(evens) // [2 4]Kebanyakan kode Go yang akan kamu baca melakukan persis hal ini. Butuh beberapa baris, tetapi setiap barisnya jelas.
PR
File PR ada di exercises/24/homework/. Setiap file bisa
langsung dijalankan dan mencetak satu baris pengganti, dan komentar
paling atasnya menyebutkan import yang kamu butuhkan.
Soal 1 — Daftar belanja
Buka exercises/24/homework/01-shopping-line.go. Slice
berisi nama barang sudah disediakan. Cetak sebagai satu baris yang
dipisahkan koma, memakai strings.Join.
Soal 2 — Tinggi ke rendah
Buka exercises/24/homework/02-high-to-low.go. Slice
berisi angka sudah disediakan. Urutkan dari tertinggi ke terendah, lalu
cetak dalam satu baris dengan strings.Join.
Soal 3 — Papan peringkat
Buka exercises/24/homework/03-leaderboard.go. Slice
berisi nama pemain yang teracak sudah disediakan. Urutkan menurut abjad
dan cetak papan peringkat bernomor, satu per baris (1. Ada,
2. Ben, dan seterusnya).
Tantangan — Tiga teratas
Buka exercises/24/homework/04-top-three.go. Slice berisi
skor sudah disediakan. Urutkan dari tertinggi, lalu cetak tiga teratas
saja dalam satu baris yang dipisahkan spasi. Pakai
slices.Sort, slices.Reverse, dan
strings.Join, ditambah pemotongan untuk mengambil tiga yang
pertama.
Stuck atau sudah selesai? Buka halaman solusi PR.