web-dev-qa-db-ja.com

1つの命令でgolangマップを初期化するにはどうすればよいですか?

これは私のコードです:

var keys map[int]string
keys = make(map[int]string)

keys[1] = "aa"
keys[2] = "ab"
keys[3] = "ac"
keys[4] = "ba"
keys[5] = "bb"
keys[6] = "bc"
keys[7] = "ca"
keys[8] = "cb"
keys[9] = "cc"

1つのステートメントや1行で同じことを実行できますか?

14
sensorario

はい、単一のステートメント(仕様では composite literal と呼ばれる)でマップを作成できます。

var keys = map[int]string{
    1: "aa",
    2: "ab",
    3: "ac",
    4: "ba",
    5: "bb",
    6: "bc",
    7: "ca",
    8: "cb",
    9: "cc",
}

または、関数内にいる場合は、 短い変数宣言 を使用できます。

keys := map[int]string{
    1: "aa",
    2: "ab",
    3: "ac",
    4: "ba",
    5: "bb",
    6: "bc",
    7: "ca",
    8: "cb",
    9: "cc",
}
41
Tim Cooper

キーと値の間にロジックがある場合、ループを使用してマップを初期化することもできます。ロジックをループ本体に「挿入」します。これは、特にキーと値のペアの数が多い場合に、すべてのキーと値のペアを列挙する composite literal を使用するよりも大幅に短くなる可能性があります。

あなたの例はこれで実装できます:

m := map[int]string{}
for i := 0; i < 9; i++ {
    m[i+1] = string("abc"[i/3]) + string("abc"[i%3])
}
fmt.Println(m)

出力( Go Playground で試してください):

map[5:bb 8:cb 4:ba 2:ab 3:ac 6:bc 7:ca 9:cc 1:aa]

このソリューションのバリアント(異なるロジック実装を使用):

m := map[int]string{}
for i := 0; i < 9; i++ {
    m[i+1] = "abc"[i/3:i/3+1] + "abc"[i%3:i%3+1]
}
fmt.Println(m)

出力は「同じ」です。 Go Playground でこのバリアントを試してください。

さらに、ループ本体のみを投稿するソリューション(プレイグラウンドリンク: another#1another#2 ):

// Another #1:
m[i+1] = fmt.Sprintf("%c%c", "abc"[i/3], "abc"[i%3])
// Another #2:
m[i+1] = fmt.Sprintf("%c%c", 'a'+i/3, 'a'+i%3)

別のアプローチでは、値を生成し、値からキーを計算する2つのループ(埋め込み)を使用する場合があります。

for i := 'a'; i <= 'c'; i++ {
    for j := 'a'; j <= 'c'; j++ {
        m[int((i-'a')*3+j-'a'+1)] = string(i) + string(j)
    }
}

Go Playground でこれを試してください。

値の数が多くない場合、別の実行可能なアプローチは、1つのstring値内のすべての要素を列挙し、サブスライスを使用することです(新しいバッキング配列が作成されないため効率的です。文字列は共有されます):

const s = "aaabacbabbbccacbcc"

m := map[int]string{}
for i := 0; i < 9; i++ {
    m[i+1] = s[i*2 : i*2+2]
}
fmt.Println(m)

出力( Go Playground でこれを試してください):

map[9:cc 1:aa 2:ab 5:bb 8:cb 3:ac 4:ba 6:bc 7:ca]

また、キーがint型で、キーのセットが(多かれ少なかれ)連続している場合、代わりにスライスを使用する方が効率的(メモリとパフォーマンスの両方)であることが多いことに注意してください。

m := make([]string, 10)
for i := 0; i < 9; i++ {
    m[i+1] = fmt.Sprintf("%c%c", 'a'+i/3, 'a'+i%3)
}
fmt.Printf("%q\n", m)

m2 := []string{"", "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc"}
fmt.Printf("%q\n", m2)

m3 := []string{1: "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc"}
fmt.Printf("%q\n", m3)

出力( Go Playground で試してください):

["" "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc"]
["" "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc"]
["" "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc"]

3番目の例でわかるようにm3、複合リテラルでオプションのインデックスを使用して、後続の値のインデックスを指定できます。詳細はこちら: golang配列初期化のキー付きアイテム

7
icza

私の好ましいアプローチは、短い変数宣言の複合リテラルです。場合によっては、関数が混乱を減らすのに役立つことがあります。

package main

import (
    "fmt"
)

// initMap initializes a map with an integer key starting at 1
func initMap(sa []string) map[int]string {
    m := make(map[int]string, len(sa))
    for k, v := range sa {
        m[k+1] = v // add 1 to k as it is starting at base 0
    }
    return m
}

// main is the entry point of any go application
func main() {
    // My preferred approach is a composite literal in a short variable declaration
    keys := map[int]string{1: "aa", 2: "ab", 3: "ac", 4: "ba", 5: "bb", 6: "bc", 7: "ca", 8: "cb", 9: "cc"}
    fmt.Println(keys)

    // Using a function to initialize the map might help to avoid clutter
    keys2 := initMap([]string{"aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc"})
    fmt.Println(keys2)
}

https://play.golang.org/p/Rrb9ChBkXW で実際の動作をご覧ください

1
Peter Gloor