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()
}
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.
No, slices cannot be used as map keys as they have no equality defined. Save this answer.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With