119

如果我有一张地图 m 是否有更好的方法来获取值 v 的一部分而不是

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)
 }

有地图的内置功能吗?Go 包中是否有一个函数,或者如果我必须这样做,这是最好的代码吗?

4

5 回答 5

74

作为 jimt 帖子的补充:

您也可以使用append而不是显式地将值分配给它们的索引:

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。这样做是为了append不需要在每次切片容量v用完时分配内存。

您也可以make在没有容量值的情况下切片,并append为自己分配内存。

于 2012-11-17T05:20:16.463 回答
72

很不幸的是,不行。没有内置的方法可以做到这一点。

作为旁注,您可以在创建切片时省略容量参数:

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

这里暗示容量与长度相同。

于 2012-11-16T18:52:55.513 回答
7

不一定更好,但更简洁的方法是定义切片长度和容量,例如txs := make([]Tx, 0, len(txMap))

    // Defines the Slice capacity to match the Map elements count
    txs := make([]Tx, 0, len(txMap))

    for _, tx := range txMap {
        txs = append(txs, tx)
    }

完整示例:

package main

import (
    "github.com/davecgh/go-spew/spew"
)

type Tx struct {
    from  string
    to    string
    value uint64
}

func main() {
    // Extra touch pre-defining the Map length to avoid reallocation
    txMap := make(map[string]Tx, 3)
    txMap["tx1"] = Tx{"andrej", "babayaga", 10}
    txMap["tx2"] = Tx{"andrej", "babayaga", 20}
    txMap["tx3"] = Tx{"andrej", "babayaga", 30}

    txSlice := getTXsAsSlice(txMap)
    spew.Dump(txSlice)
}

func getTXsAsSlice(txMap map[string]Tx) []Tx {
    // Defines the Slice capacity to match the Map elements count
    txs := make([]Tx, 0, len(txMap))
    for _, tx := range txMap {
        txs = append(txs, tx)
    }

    return txs
}

简单的解决方案,但有很多陷阱。阅读这篇博文了解更多详情:https ://web3.coach/golang-how-to-convert-map-to-slice-three-gotchas

于 2020-05-22T10:49:12.650 回答
1

据我目前所知,go 没有一种方法可以将字符串/字节连接到生成的字符串中,而无需制作至少 /two/ 副本。

您目前必须增加一个 []byte,因为所有字符串值都是 const,然后您必须使用内置的字符串让语言创建一个“祝福”字符串对象,它将复制缓冲区,因为某处可能有引用到支持 [] 字节的地址。

如果 []byte 是合适的,那么您可以在 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)
}
于 2017-03-16T23:50:37.143 回答
1

你可以使用这个maps包:

go get https://github.com/drgrib/maps

那么你只需要打电话

values := maps.GetValuesIntString(m)

对于该常见map组合,它是类型安全的。您可以在同一包中使用该工具generate的任何其他类型的其他类型安全功能。mapmapper

完全披露:我是这个包的创建者。我创建它是因为我发现自己map反复重写这些函数。

于 2019-02-05T23:42:11.350 回答