10-bo‘lim

Maplar

Kalit-qiymat saqlash, comma-ok tekshiruvi, o'chirish, tartibning ataylab tasodifiyligi va uni saralab chiqarish usuli.

🕑 15 daqiqa o‘qish 📄 696 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Yaratish va ishlatish
  2. Bo'sh map yaratish
  3. Kalit bor-yo'qligini bilish
  4. Tekshirib ishlatish
  5. O'chirish
  6. Tartib - ataylab tasodifiy
  7. Saralab chiqarish
  8. maps paketi
  9. Map ham ko'rsatkich kabi
  10. Murakkabroq qiymatlar
  11. To'plam yasash
  12. Xulosa

map - kalit bo'yicha qiymat saqlaydigan tur. Boshqa tillarda uni lug'at, hash yoki assotsiativ massiv deb atashadi.

Yaratish va ishlatish #

Go
package main

import "fmt"

func main() {
    yoshlar := map[string]int{
        "Husanboy": 25,
        "Malika":   20,
        "Nodira":   22,
    }

    fmt.Println(yoshlar["Malika"])
    fmt.Println(len(yoshlar))

    yoshlar["Aziza"] = 19
    yoshlar["Malika"] = 21

    fmt.Println(len(yoshlar), yoshlar["Malika"])
}
Natija
20
3
4 21

map[kalit]qiymat - kalit turi kvadrat qavs ichida, qiymat turi undan keyin.

Mavjud kalitga yozsangiz, qiymat almashadi; yangi kalitga yozsangiz, u qo'shiladi.

Bo'sh map yaratish #

Go
package main

import "fmt"

func main() {
    ballar := make(map[string]int)
    ballar["Kamola"] = 95
    fmt.Println(ballar)

    var buzuq map[string]int
    fmt.Println(buzuq == nil, len(buzuq))
    fmt.Println(buzuq["yoq"])
}
Natija
map[Kamola:95]
true 0
0
nil map ga yozib bo'lmaydi

var buzuq map[string]int - bu nil map. Undan o'qish xavfsiz (nol qiymat qaytadi), lekin unga yozish dasturni to'xtatadi:

KOD
panic: assignment to entry in nil map

Bu slice bilan farq qiladigan joy: nil slicega append qilish mumkin edi, nil map ga esa yozib bo'lmaydi.

Shuning uchun map ni doim make bilan yoki map[string]int{} shaklida yarating.

Kalit bor-yo'qligini bilish #

Go
package main

import "fmt"

func main() {
    ballar := map[string]int{"Malika": 88, "Aziza": 0}

    fmt.Println(ballar["Malika"])
    fmt.Println(ballar["Dilnoza"])

    ball, bormi := ballar["Aziza"]
    fmt.Println(ball, bormi)

    ball2, bormi2 := ballar["Dilnoza"]
    fmt.Println(ball2, bormi2)
}
Natija
88
0
0 true
0 false

Mana muammo: ballar["Dilnoza"] ham 0 beradi, ballar["Aziza"] ham. Lekin birinchisi yo'q, ikkinchisi esa haqiqatan nolga teng.

Ularni ajratish uchun ikkinchi qiymat olinadi. Bu shakl "comma-ok" deb ataladi.

comma-ok - Go ning takrorlanuvchi naqshi

Bu shaklni Go da uch joyda ko'rasiz:

Go
qiymat, bormi := map[kalit]
qiymat, ochiq := <-kanal
qiymat, mos := interfeys.(Tur)

Uchalasida ham ikkinchi qiymat bool va u "amal muvaffaqiyatli bo'ldimi" degan savolga javob beradi.

Kanallarni 19-, tur tekshiruvini 13-bo'limda ko'ramiz.

Tekshirib ishlatish #

Go
package main

import "fmt"

func main() {
    narxlar := map[string]int{
        "Olma": 12000,
        "Anor": 18000,
    }

    if narx, bormi := narxlar["Olma"]; bormi {
        fmt.Println("Olma narxi:", narx)
    }

    if _, bormi := narxlar["Uzum"]; !bormi {
        fmt.Println("Uzum topilmadi")
    }
}
Natija
Olma narxi: 12000
Uzum topilmadi

5-bo'limdagi boshlang'ich qismli if bu yerda juda qulay: tekshiruv va ishlatish bitta blokda.

O'chirish #

Go
package main

import "fmt"

func main() {
    shaharlar := map[string]string{
        "NAM": "Namangan",
        "AND": "Andijon",
        "BUX": "Buxoro",
    }

    delete(shaharlar, "AND")
    fmt.Println(len(shaharlar))

    delete(shaharlar, "YOQ")
    fmt.Println(len(shaharlar))

    clear(shaharlar)
    fmt.Println(len(shaharlar))
}
Natija
2
2
0

delete mavjud bo'lmagan kalitni o'chirishga urinsa, hech narsa qilmaydi va xato ham bermaydi.

clear - hammasini o'chiradi. U Go 1.21 da qo'shilgan.

Tartib - ataylab tasodifiy #

Go
package main

import "fmt"

func main() {
    yoshlar := map[string]int{
        "Husanboy": 25,
        "Malika":   20,
        "Nodira":   22,
    }

    fmt.Println(yoshlar)
    fmt.Println(len(yoshlar))
}
Natija
map[Husanboy:25 Malika:20 Nodira:22]
3

Bu yerda natija saralangan ko'rinadi - lekin bu fmt ning xizmati, map ning emas.

range bo'yicha tartib har safar boshqacha

fmt.Println(yoshlar) map ni chop etganda, fmt paketi kalitlarni o'zi saralaydi. Shuning uchun yuqoridagi natija barqaror.

Lekin range bilan yurganingizda tartib kafolatlanmaydi:

Go
for kalit := range yoshlar {
    fmt.Println(kalit)
}

Bu kod har safar boshqa tartibda chiqaradi. Bir xil dastur, bir xil ma'lumot - lekin har ishga tushirishda boshqa natija.

Bu xato emas, balki ataylab qilingan. Go jamoasi tartibni qasddan tasodifiy qildi, chunki aks holda dasturchilar unga bilmasdan tayanib qolar edi. Keyin esa Go ning ichki tuzilishi o'zgarganda ularning kodi buzilardi.

Tartib kerak bo'lsa, uni o'zingiz ta'minlaysiz.

Saralab chiqarish #

Go
package main

import (
    "fmt"
    "slices"
)

func main() {
    yoshlar := map[string]int{
        "Husanboy": 25,
        "Malika":   20,
        "Nodira":   22,
        "Aziza":    19,
    }

    kalitlar := make([]string, 0, len(yoshlar))
    for kalit := range yoshlar {
        kalitlar = append(kalitlar, kalit)
    }
    slices.Sort(kalitlar)

    for _, kalit := range kalitlar {
        fmt.Printf("%-10s %d\n", kalit, yoshlar[kalit])
    }
}
Natija
Aziza      19
Husanboy   25
Malika     20
Nodira     22

Bu standart Go naqshi: kalitlarni yig', sarala, keyin yur.

Uni har safar qo'lda yozish shart emas - maps paketi yordam beradi.

maps paketi #

Go
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    narxlar := map[string]int{
        "Olma": 12000,
        "Anor": 18000,
        "Uzum": 22000,
    }

    kalitlar := slices.Sorted(maps.Keys(narxlar))
    fmt.Println(kalitlar)

    qiymatlar := slices.Sorted(maps.Values(narxlar))
    fmt.Println(qiymatlar)

    nusxa := maps.Clone(narxlar)
    nusxa["Olma"] = 1
    fmt.Println(narxlar["Olma"], nusxa["Olma"])
}
Natija
[Anor Olma Uzum]
[12000 18000 22000]
12000 1

maps.Keys kalitlarni ketma-ketlik sifatida qaytaradi, slices.Sorted esa uni saralangan slicega aylantiradi.

Bu ikki paket Go 1.21-1.23 da qo'shilgan; eski Go da yuqoridagi qo'lda yozilgan shaklni ishlatasiz.

Map ham ko'rsatkich kabi #

Go
package main

import "fmt"

func qoshimcha(m map[string]int) {
    m["yangi"] = 100
}

func main() {
    ballar := map[string]int{"eski": 50}
    qoshimcha(ballar)
    fmt.Println(len(ballar), ballar["yangi"])
}
Natija
2 100

& yozilmagan, lekin o'zgarish saqlandi. Map ichida ham ma'lumotga ko'rsatkich bor - xuddi slice kabi.

Map ni nusxalash uchun Clone kerak

nusxa := asl deb yozsangiz, ikkala o'zgaruvchi ham bitta map ga ko'rsatadi. Biriga yozsangiz, ikkinchisida ham ko'rinadi.

Haqiqiy nusxa uchun maps.Clone(asl) ishlating - yuqoridagi misolda shunday qilingan.

Murakkabroq qiymatlar #

Go
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    guruhlar := map[string][]string{
        "A": {"Malika", "Nodira"},
        "B": {"Husanboy"},
    }

    guruhlar["B"] = append(guruhlar["B"], "Aziza")
    guruhlar["C"] = append(guruhlar["C"], "Kamola")

    for _, g := range slices.Sorted(maps.Keys(guruhlar)) {
        fmt.Printf("%s: %v\n", g, guruhlar[g])
    }
}
Natija
A: [Malika Nodira]
B: [Husanboy Aziza]
C: [Kamola]

Diqqat qiling: guruhlar["C"] hali mavjud emas edi, lekin append ishladi.

Sababi - mavjud bo'lmagan kalit nil slice qaytaradi, nil slicega esa append qilish mumkin (9-bo'lim).

To'plam yasash #

Go
package main

import (
    "fmt"
    "slices"
)

func main() {
    korilgan := map[string]bool{}

    sozlar := []string{"olma", "anor", "olma", "uzum", "anor"}

    takrorsiz := []string{}
    for _, s := range sozlar {
        if !korilgan[s] {
            korilgan[s] = true
            takrorsiz = append(takrorsiz, s)
        }
    }

    fmt.Println(takrorsiz)
    fmt.Println(len(korilgan))

    saralangan := slices.Clone(takrorsiz)
    slices.Sort(saralangan)
    fmt.Println(saralangan)
}
Natija
[olma anor uzum]
3
[anor olma uzum]

Go da alohida "to'plam" turi yo'q. Uning o'rniga map[string]bool yoki map[string]struct{} ishlatiladi.

Bu yerda korilgan[s] mavjud bo'lmagan kalit uchun false qaytargani ish beradi - qo'shimcha tekshiruv kerak emas.

map[string]struct{} nima uchun

Ba'zan map[string]struct{} shaklini ko'rasiz. struct{} - bo'sh struktura, u umuman joy egallamaydi.

bool har bir element uchun bir bayt oladi; million elementli to'plamda bu bir megabayt. struct{} esa nol.

Farqi shundaki, yozish uzunroq bo'ladi: korilgan[s] = struct{}{}. Shuning uchun kichik to'plamlar uchun bool yetarli va o'qishliroq.

Amaliy topshiriq
  1. Ism va yoshni saqlaydigan map yarating.
  2. nil map ga yozishga urinib, vahima matnini ko'ring.
  3. comma-ok bilan mavjud va mavjud bo'lmagan kalitni ajrating.
  4. Nolga teng qiymat va yo'q kalit farqini ko'rsating.
  5. delete va clear ni sinang.
  6. range bilan bir necha marta chiqarib, tartib o'zgarishini ko'ring.
  7. Kalitlarni saralab, tartibli chiqaring.
  8. maps.Clone bilan mustaqil nusxa oling.
  9. map[string][]string bilan guruhlar tuzing.
  10. Map yordamida takrorlarni olib tashlang.

Xulosa #

  • map[kalit]qiymat - kalit bo'yicha saqlash; make yoki literal bilan yaratiladi.
  • nil map dan o'qish mumkin, yozib bo'lmaydi - bu vahima keltiradi.
  • Mavjud bo'lmagan kalit nol qiymat beradi; borligini bilish uchun comma-ok shakli.
  • delete yo'q kalitga befarq; clear hammasini o'chiradi.
  • range bo'yicha tartib ataylab tasodifiy; fmt esa chop etishda kalitlarni o'zi saralaydi.
  • Tartib kerak bo'lsa: kalitlarni yig'ib, slices.Sort bilan saralang.
  • Map ichida ko'rsatkich bor - funksiyaga uzatilganda o'zgarish saqlanadi; nusxa uchun maps.Clone.
  • To'plam uchun map[string]bool yoki map[string]struct{} ishlatiladi.

Keyingi bo'limda strukturalarni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.