golangの日記

Go言語を中心にプログラミングについてのブログ

Go言語(golang) map の初期化と使い方

golang.png


連想配列(他言語のhashやdict)は、Go言語では map です。





目次



マップの初期化


初期化時にキーと値のセットを一度に行う

m := map[string]int{"foo": 100, "bar": 200, "baz": 300}

// キーの値を取り出すには m[キー名] とする
fmt.Println(m["foo"]) // 100
fmt.Println(m["bar"]) // 200
fmt.Println(m["baz"]) // 300


makeを使って初期化

make で map を初期化する場合の第二引数には、キャパシティ(容量)を指定。 キャパシティを指定しない場合は必要十分なキャパシティが自動的に確保される。

m := make(map[string]int, 3)
// キャパシティは省略可能
// m := make(map[string]int)

m["foo"] = 100
m["bar"] = 200
m["baz"] = 300

fmt.Println(m["foo"]) // 100
fmt.Println(m["bar"]) // 200
fmt.Println(m["baz"]) // 300


マップリテラルで初期化

この場合もキャパシティは自動で確保される。

m := map[string]int{}

m["foo"] = 100
m["bar"] = 200
m["baz"] = 300

fmt.Println(m["foo"]) // 100
fmt.Println(m["bar"]) // 200
fmt.Println(m["baz"]) // 300


map を使う場合によくあるエラー (assignment to entry in nil map)

マップを初期化していない状態(nil)で値をセットするとパニックする。

panic: assignment to entry in nil map

なのでvarで宣言しただけの場合には注意する必要がある。

var m map[string]int

// 初期化していない状態で値をセットしようとするとパニックする
m["key"] = 100

マップが nil かどうか確認してから初期化するか予め初期化しておく

var m map[string]int

if m == nil {
    m = make(map[string]int)
}

m["key"] = 100


基本的な使い方


追加

m[キー名] = 値 で追加できる。

m := map[string]int{}

m["bar"] = 200

fmt.Println(m["bar"]) // 200


値の変更

同じキー名に値を代入することで変更することができる。

m := map[string]int{"foo": 10}

fmt.Println(m["foo"]) // 10 変更前

// 値の変更
m["foo"] = 1000

fmt.Println(m["foo"]) // 1000


削除

ビルトイン関数 delete にマップと削除するキー名を指定する。

m := map[string]int{"foo": 100}

// 第一引数に map を指定、第二引数に キー名を指定する
delete(m, "foo")

_, isThere := m["foo"]
fmt.Println(isThere) // false


map 自体の削除

nil にするだけ。

削除後にキーと値をセットしようとするとエラーになるので、また同じ変数を使う場合は初期化する必要がある。

m := map[string]int{"foo": 100, "bar": 200, "baz": 300}

// nil を代入して削除
m = nil

fmt.Println(len(m))


キーの個数

配列と同じで len を使う

m := map[string]int{"foo": 100, "bar": 200, "baz": 300}

fmt.Println(len(m)) // 3


キーの存在確認

2つ目の変数が真偽値になっているのでそれで確認できる。

m := map[string]int{"foo": 100}

// それぞれキーの値と、キーが存在するかを示す真偽値(bool)
value, isThere := m["foo"]
fmt.Println(value, isThere) // 100, true

// キーが存在しなければ false
value, isThere = m["bar"]
fmt.Println(value, isThere) // 0, false


キーのみ取得

go言語の map には m.keys() のような便利な関数はないので for range で愚直にキーをスライスにする

m := map[string]int{"foo": 100, "bar": 200, "baz": 300}

// append を使うより make で長さと容量を指定して
// keys[i] = key とした方がメモリの再割当てがないので実行速度が速くなる
keys := make([]string, len(m), len(m))

i := 0
for key := range m {
    keys[i] = key
    i++
}

fmt.Println(keys) // [bar baz foo] ※注意: キーの順番は保証されない



map のループ


for ... range

m := map[string]int{"foo": 100, "bar": 200, "baz": 300}

// キーのみ取り出す
for key := range m {
    fmt.Println(key)
}

// キーと値
for key, value := range m {
    fmt.Println(key, value)
}

// 値のみ必要な場合
for _, value := range m {
    fmt.Println(value)
}

// ループの回数を数える
i := 0
for key, value := range m {
    fmt.Println(key, value)
    i++
}


キーでソートして順番通りに列挙する

キーをスライス(配列)にして、それをソートする。
そのソートしたキーのスライスを使って何らかの順序でマップの値を取り出す。

m := map[string]int{"B": 100, "C": 200, "A": 300}

a := make([]string, len(m), len(m))

i := 0
for key := range m {
    a[i] = key
    i++
}

// キーを入れたスライスをソートする
sort.Strings(a)

for i := 0; i < len(a); i++ {
    fmt.Println(a[i], m[a[i]])
}



2つのマップが同じかどうか確認

reflect.DeepEqual を使って2つのマップがどちらも同じキーと値を持っているか調べる。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    m1 := map[string]int{"A": 100, "B": 200, "C": 300}
    
    m2 := map[string]int{"B": 200, "C": 300, "A": 100}
    isSame := reflect.DeepEqual(m1, m2)
    fmt.Println(isSame) // true

    // 値が異なるマップ
    m3 := map[string]int{"C": 100, "B": 300, "A": 200}
    isSame = reflect.DeepEqual(m1, m3)
    fmt.Println(isSame) // false
}



キーの型


rune (int32)

m := map[rune]int{}
m['あ'] = 100
println(m['あ']) // 100


真偽値

m := map[bool]string{
    true:  "value-1",
    false: "value-2",
}

println(m[10/2 == 5]) // value-1


ポインター

m := map[*string]int{}
key1 := "key"
key2 := "key"
key3 := "key"
m[&key1] = 100
m[&key2] = 200
m[&key3] = 300

for k, v := range m {
    fmt.Println(*k, v)
}


インターフェイス

m := map[interface{}]int{}
m[interface{}("key")] = 100
m[interface{}(true)] = 200
m[interface{}(300)] = 300

println(m[interface{}("key")]) // 100
println(m[interface{}(true)])  // 200
println(m[interface{}(300)])   // 300


構造体

type Key struct {
    name string
}

m := map[Key]int{}

m[Key{"foo"}] = 100
m[Key{"bar"}] = 100
m[Key{"baz"}] = 100

for k, v := range m {
    println(k.name, v)
}