Golang map range遍历结果不稳定问题

闲言少叙,本文主要是想介绍一个Golang开发常见的一个问题。然而,此问题对于初学者来说却经常容易陷入坑中。


问题

我在写一段代码时,使用了Golang的map数据结构,目的是想用map缓存计数结果。简单来说map的键也是整型的,且以递增顺序存储。我的最初想法是,在统计结束后,按照map中存储的键有序输出值。可是,当我运行程序时,结果并不是我想要的,而且有一定概率运行结果不同。

问题代码

func sortByBits(arr []int) []int {
    var bitmap = make(map[int][]int, 0)
    // map缓存
    for i := 0; i < len(arr); i++ {
        bits := calBits(arr[i])
        if _, ok := bitmap[bits]; !ok {
            tmp := make([]int, 0)
            tmp = append(tmp, arr[i])
            bitmap[bits] = tmp
        } else {
            bitmap[bits] = append(bitmap[bits], arr[i])
            for j := len(bitmap[bits]) - 1;j > 0; j-- {
                if bitmap[bits][j] < bitmap[bits][j - 1] {
                    bitmap[bits][j], bitmap[bits][j - 1] = bitmap[bits][j - 1], bitmap[bits][j]
                }
            }
        }
    }
    // 输出
    var res []int
    for _, value := range bitmap {
        res = append(res, value...)
    }
    return res
}
func calBits(n int) int {
    sum := 0
    for n > 0 {
        if n & 1 == 1 {
            sum++
        }
        n = n >> 1
    }
    return sum
}

当发现这个问题后,我使用二维数组替换map,改造代码如下:

改造代码

func sortByBits(arr []int) []int {
    var bitmap = make([][]int, 0, 10000)
    // map缓存
    for i := 0; i < len(arr); i++ {
        bits := calBits(arr[i])
        if len(bitmap) <= bits {
            length := bits - len(bitmap) + 1
            for j := 0; j < length; j++ {
                tmp := make([]int, 0)
                bitmap = append(bitmap, tmp)
            }
        }
           
        if len(bitmap[bits]) == 0 {
            bitmap[bits] = append(bitmap[bits], arr[i])
        } else {
            bitmap[bits] = append(bitmap[bits], arr[i])
            for j := len(bitmap[bits]) - 1;j > 0; j-- {
                if bitmap[bits][j] < bitmap[bits][j - 1] {
                    bitmap[bits][j], bitmap[bits][j - 1] = bitmap[bits][j - 1], bitmap[bits][j]
                }
            }
        }
    }
    // 输出
    var res []int
    for _, value := range bitmap {
        res = append(res, value...)
    }
    return res
}
func calBits(n int) int {
    sum := 0
    for n > 0 {
        if n & 1 == 1 {
            sum++
        }
        n = n >> 1
    }
    return sum
}

代码很简单,问题也很简单。原理就是Golang的map按键输出结果是随机的,这是语言本身的一个特性,或者说是"坑"。作为开发者,要熟练掌握语言最基本特性,才能开发出最稳健的程序。

你可能感兴趣的:(Gopher,服务端开发)