Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Join map keys in golang

Tags:

go

I want to join all of the keys of a map into a single string of the form [k1, k2, ...]. I'm not overly concerned with the order, just that I can make the string. I know that there is the function strings.Join() but it takes in a []string and not a map[string]bool.

I want to do this in the most efficient/fastest way possible (i.e. I don't want to create an entire copy of the keys just so I can slice over it). I couldn't find a way to just get a slice of the map's keys, so I came up with the following function instead. Obviously it's not the greatest because it does an unnecessary write and trunc.

Is there a way to just slice over the map keys?

func CreateStringArray(myMap map[string]bool) string {
    if myMap == nil || len(myMap) == 0 {
        return "[ ]"
    }

    buf := bytes.NewBufferString("[")

    for k, _ := range myMap {
        buf.WriteString(k)
        buf.WriteString(", ")
    }

    buf.Truncate(buf.Len() - 2)
    buf.WriteString("]")

    return buf.String()
}
like image 373
FuriousGeorge Avatar asked Jan 03 '15 01:01

FuriousGeorge


People also ask

How do you get the map key in Golang?

You can retrieve the value assigned to a key in a map using the syntax m[key] . If the key exists in the map, you'll get the assigned value. Otherwise, you'll get the zero value of the map's value type.

Can slice Be map key in Golang?

No, slices cannot be used as map keys as they have no equality defined. Save this answer.

Can array be a key of map Golang?

The data types like slice and noncomparable arrays and structs or the custom data types which are not comparable don't use as a map key. In maps, the values are not unique like keys and can be of any type like int, float64, rune, string, pointer, reference type, map type, etc.


1 Answers

Most of the time, I'd just write the obvious code:

func KeysString(m map[string]bool) string {
    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }
    return "[" + strings.Join(keys, ", ") + "]"
}

If you need efficiency more than readability, you can look at the implementation of strings.Join for an idea on how to write this minimising copies. The main difference between this and your code is that a []byte of exactly the right length is constructed which prevents the data being copied around when the buffer has to resize as the result is getting built up.

func KeysString(m map[string]bool) string {
    if len(m) == 0 {
        return "[]"
    }
    n := 2 * len(m)  // (len-1) commas (", "), and one each of "[" and "]".
    for k := range m {
        n += len(k)
    }
    b := make([]byte, n)
    bp := copy(b, "[")
    first := true
    for k := range m {
        if !first {
            bp += copy(b[bp:], ", ")
        }
        bp += copy(b[bp:], k)
        first = false
    }
    bp += copy(b[bp:], "]")
    return string(b)
}

Of course, be sure to profile and optimise in the context of the code you're using this function to make sure the readability tradeoff is actually worth it.

like image 84
Paul Hankin Avatar answered Sep 23 '22 18:09

Paul Hankin