2012-11-16 4 views
47

私はマップMを使用している場合の値のスライスを得るためのより良い方法があるが golangには、マップから値のスライスを得る良い方法がありますか?

package main 
import (
    "fmt" 
) 

func main() { 
    m := make(map[int]string) 

    m[1] = "a" 
    m[2] = "b" 
    m[3] = "c" 
    m[4] = "d" 

    // Can this be done better? 
    v := make([]string, len(m), len(m)) 
    idx := 0 
    for _, value := range m { 
     v[idx] = value 
     idx++ 
    } 

    fmt.Println(v) 
} 

その後、

をVマップの構築された機能はありますか? Goパッケージには関数がありますか、これは私がする必要がある場合に行う最良のコードですか?

+0

代わりにあなたのforループの中に「_」を、あなたはそれがキー、値ではないインデックス、値を返すマップ範囲に及ぶときはありません、彼は、できないIDXそれを呼び出すと、IDX ++ビジネス –

+0

を捨てます。彼の例では、最初のキーとして1を使用し、スライスのインデックスを正しくないようにします。なぜなら、開始インデックスはゼロではなく1になり、4になると範囲外になるからです。 https://play.golang.org/p/X8_SbgxK4VX – Popmedic

答えて

29

残念ながら、これを行うための組み込み方法はありません。

側の注意点として、あなたは、スライスの作成に容量引数を省略することができます容量は、ここで長さと同じになるように暗示され

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

。あなたはまたappendを使用するのではなく、明示的にそのインデックスに値を割り当てることができる

28
JIMTのポストに加えとして

長さ(未要素存在)がゼロである

m := make(map[int]string) 

m[1] = "a" 
m[2] = "b" 
m[3] = "c" 
m[4] = "d" 

v := make([]string, 0, len(m)) 

for _, value := range m { 
    v = append(v, value) 
} 

留意されたい。しかし容量(割り当てられたスペース)は、mの要素の数で初期化されます。これは、スライスvの容量がなくなるたびにメモリを割り当てる必要がないので、appendが実行されます。

また、容量値のないスライスをmakeにして、appendにメモリを割り当てさせることもできます。

+0

これがもっと遅くなるのではないかと思っていました。私はmap [int] intで粗雑なベンチマークを行い、それは約1〜2%遅くなっていたようです。これが心配するものであればどんな考えですか? – masebase

+1

私は少し遅くなることを追加すると思いますが、その違いはほとんどの場合無視できます。 [直接割り当てと追加を比較したベンチマーク](http://pastie.org/5393131)。 – nemo

0

私が現在知っている限り、goには、少なくとも2つのコピーを作成することなく、結果の文字列に文字列/バイトを連結する方法がありません。

現在、すべての文字列値がconstなので、現在は[]バイトを拡張する必要があります。次に、組み込みの文字列を使用して言語に「blessed」文字列オブジェクトを作成する必要があります。 []バイトを裏付けるアドレスへの参照を持つことができます。

[]バイトが適切な場合は、1つの割り当てを行い、コピーを実行することによって、bytes.Join関数を介してごくわずかなリードを得ることができます。

package main 
import (
    "fmt" 
) 

func main() { 
m := make(map[int]string) 

m[1] = "a" ; m[2] = "b" ;  m[3] = "c" ; m[4] = "d" 

ip := 0 

/* If the elements of m are not all of fixed length you must use a method like this; 
* in that case also consider: 
* bytes.Join() and/or 
* strings.Join() 
* They are likely preferable for maintainability over small performance change. 

for _, v := range m { 
    ip += len(v) 
} 
*/ 

ip = len(m) * 1 // length of elements in m 
r := make([]byte, ip, ip) 
ip = 0 
for _, v := range m { 
    ip += copy(r[ip:], v) 
} 

// r (return value) is currently a []byte, it mostly differs from 'string' 
// in that it can be grown and has a different default fmt method. 

fmt.Printf("%s\n", r) 
} 
関連する問題