为什么不能按插入顺序迭代地图?

时间:2015-03-08 18:44:57

标签: dictionary go

我有一个导航栏作为地图:

var navbar = map[string]navbarTab{
}

navbarTab具有各种属性,子项等。当我尝试渲染导航栏(使用for tabKey := range navbar)时,它会以随机顺序显示。我知道range在运行时会随机排序,但似乎无法获得有序的键列表或按插入顺序迭代。

游乐场链接在这里:http://play.golang.org/p/nSL1zhadg5虽然它似乎没有表现出相同的行为。

如何在不破坏广告订单的情况下迭代此地图?

2 个答案:

答案 0 :(得分:24)

地图数据结构的通用概念是它是键值对的集合。 “有序”“已排序”未提及。

Wikipedia definition:

  

在计算机科学中,关联数组地图符号表字典是抽象数据类型由(key, value)对的集合组成,这样每个可能的键只在集合中出现一次。

map 是计算机科学中最有用的数据结构之一,因此Go将其作为内置类型提供。但是,语言规范仅指定常规映射(Map types):

  

映射是一种无序的一组元素,称为元素类型,由一组另一种类型的唯一键索引,称为键类型。未初始化地图的值为nil

请注意,语言规范不仅省略了“有序”“已排序”字词,而是明确指出了相反的意思:“unordered”。但为什么?因为这为运行时提供了更大的自由度来实现地图类型。语言规范允许使用任何地图实现,如 hash map, tree map等。请注意,Go的当前(和以前的)版本使用哈希映射实现,但是你不需要知道使用它。

关于这个问题,必须阅读博客文章Go maps in action

在Go 1之前,当未更改地图时,当您多次迭代其键/条目时,运行时以相同的顺序返回键。请注意,如果修改了地图,则此订单可能会更改,因为实施可能需要执行重新整理以容纳更多条目。人们开始依赖相同的迭代顺序(当地图未被更改时),因此从Go 1开始,运行时随机数映射迭代顺序故意,以引起开发人员注意订单未定义并且不能依赖。

该怎么做?

如果您需要已排序数据集(无论是键值对的集合还是其他任何内容),无论是按键类型或任意顺序定义的插入顺序或自然顺序,{{1不是正确的选择。如果您需要预定义的订单,切片(和数组)就是您的朋友。如果您需要能够通过预定义的键查找元素,则可以另外从切片构建一个映射,以允许通过键快速查找元素

首先构建map然后以正确的顺序构建切片,或者首先构建切片,然后从中构建map完全取决于您。

前面提到的 Go map in action 博客文章中有一节专门介绍Iteration order

  

当使用范围循环迭代映射时,未指定迭代顺序,并且不保证从一次迭代到下一次迭代是相同的。由于Go 1,运行时随机化地图迭代顺序,因为程序员依赖于先前实现的稳定迭代顺序。如果需要稳定的迭代顺序,则必须维护一个指定该顺序的单独数据结构。此示例使用单独的排序键片段按键顺序打印map

map[int]string

<强> P.S:

  

......虽然它似乎没有表现出相同的行为。

您似乎在Go Playground上看到“相同的迭代顺序”,因为Go Playground上的应用程序/代码的输出是缓存。一旦执行了新的但唯一的代码,其输出将保存为新的。执行相同的代码后,将显示保存的输出,而无需再次运行代码。所以基本上它与您看到的迭代顺序不同,它是完全相同的输出而不再执行任何代码。

答案 1 :(得分:18)

Go地图不保留插入顺序;你必须自己实现这种行为。

示例:

type NavigationMap struct {
    m map[string]navbarTab
    keys []string
}

func NewNavigationMap() *NavigationMap { ... }

func (n *NavigationMap) Set(k string, v navbarTab) {
    n.m[k] = v
    n.keys = append(n.keys, k)
}

此示例不完整,并未涵盖所有用例(例如,更新重复键上的插入顺序)。

如果您的用例包括多次重新插入相同的密钥(如果密钥 k 已经在地图中,则不会更新 k 的插入顺序):

func (n *NavigationMap) Set(k string, v navbarTab) {
    _, present := n.m[k]
    n.m[k] = v
    if !present {
        n.keys = append(n.keys, k)
    }
}

选择满足您要求的最简单的东西。