按插入顺序循环遍历 Map
Go 中的 Map 不保证迭代顺序,当您想要检索项目时,这可能会令人沮丧按照它们插入的顺序。虽然存在一些解决方法,但它们通常涉及使用单独的切片或创建数据重复,这可能会导致复杂性和潜在的错误。
使用键切片的解决方案
一个可行的解决方案解决方案是按插入顺序维护一个键片。当向映射添加新对时,首先检查该键是否存在于切片中。如果没有,请将密钥附加到切片中。迭代时,只需使用切片按顺序检索键并从映射中访问相应的值即可。这种方法的开销最小,因为切片仅存储键。
示例:
type Key int type Value int type OrderedMap struct { m map[Key]Value keys []Key } func NewOrderedMap() *OrderedMap { return &OrderedMap{m: make(map[Key]Value)} } func (om *OrderedMap) Set(k Key, v Value) { if _, ok := om.m[k]; !ok { om.keys = append(om.keys, k) } om.m[k] = v } func (om *OrderedMap) Range() { for _, k := range om.keys { fmt.Println(om.m[k]) } }
使用值包装器链接列表的解决方案
或者,您可以将值包装在链表结构中。每个值包装器都包含实际值和指向列表中下一个键的指针。添加新对时,将前一个值包装器的下一个指针设置为指向新键。迭代时,从第一个键开始,按照 next 指针按顺序检索值。
示例:
type Key int type Value int type ValueWrapper struct { v Value next *Key } type OrderedMap struct { m map[Key]ValueWrapper first, last *Key } func NewOrderedMap() *OrderedMap { return &OrderedMap{m: make(map[Key]ValueWrapper)} } func (om *OrderedMap) Set(k Key, v Value) { if _, ok := om.m[k]; !ok && om.last != nil { pw2 := om.m[*om.last] om.m[*om.last] = ValueWrapper{pw2.v, &k} } pw := ValueWrapper{v: v} om.m[k] = pw if om.first == nil { om.first = &k } om.last = &k } func (om *OrderedMap) Range() { for k := om.first; k != nil; { pw := om.m[*k] fmt.Println(pw.v) k = pw.next } }
比较
关键切片方法更简单,但元素删除效率较低,因为它需要在切片中进行线性搜索。值包装链表方法允许快速删除元素,使其更适合需要频繁删除的情况。
最终,最佳选择取决于您应用程序的具体要求。
以上是迭代 Go Map 时如何保持插入顺序?的详细内容。更多信息请关注PHP中文网其他相关文章!