Join map keys in golang

huangapple go评论95阅读模式
英文:

Join map keys in golang

问题

我想将一个映射的所有键连接成一个形如[k1, k2, ...]的字符串。我不太关心顺序,只要能生成字符串即可。我知道有一个函数strings.Join(),但它接受的是[]string而不是map[string]bool

我想以最高效/最快的方式完成这个任务(即我不想创建整个键的副本,只是为了能够对其进行切片)。我找不到直接获取映射键的切片的方法,所以我想出了下面的函数。显然,这个函数并不是最好的,因为它进行了不必要的写入和截断操作。

有没有办法直接对映射的键进行切片?

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()
}
英文:

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

答案1

得分: 18

大多数情况下,我只会写出显而易见的代码:

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, ", ") + "]"
}

如果你需要效率而不是可读性,你可以参考strings.Join的实现来写一个减少拷贝的版本。这个版本与你的代码的主要区别在于,它构建了一个长度恰好合适的[]byte,这样当缓冲区需要调整大小时,数据就不会被复制。

func KeysString(m map[string]bool) string {
    if len(m) == 0 {
        return "[]"
    }
    n := 2 * len(m)  // (len-1) 个逗号(", "),以及一个左括号和一个右括号。
    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)
}

当然,一定要在使用这个函数的代码上下文中进行性能分析和优化,以确保可读性的权衡实际上是值得的。

英文:

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.

huangapple
  • 本文由 发表于 2015年1月3日 09:57:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/27750982.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定