解決Golang map range遍歷結(jié)果不穩(wěn)定問(wèn)題
閑言少敘,本文主要是想介紹一個(gè)Golang開(kāi)發(fā)常見(jiàn)的一個(gè)問(wèn)題。然而,此問(wèn)題對(duì)于初學(xué)者來(lái)說(shuō)卻經(jīng)常容易陷入坑中。
問(wèn)題
我在寫一段代碼時(shí),使用了Golang的map數(shù)據(jù)結(jié)構(gòu),目的是想用map緩存計(jì)數(shù)結(jié)果。簡(jiǎn)單來(lái)說(shuō)map的鍵也是整型的,且以遞增順序存儲(chǔ)。我的最初想法是,在統(tǒng)計(jì)結(jié)束后,按照map中存儲(chǔ)的鍵有序輸出值。可是,當(dāng)我運(yùn)行程序時(shí),結(jié)果并不是我想要的,而且有一定概率運(yùn)行結(jié)果不同。
問(wèn)題代碼
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
}
當(dāng)發(fā)現(xiàn)這個(gè)問(wèn)題后,我使用二維數(shù)組替換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
}
代碼很簡(jiǎn)單,問(wèn)題也很簡(jiǎn)單。原理就是Golang的map按鍵輸出結(jié)果是隨機(jī)的,這是語(yǔ)言本身的一個(gè)特性,或者說(shuō)是"坑"。作為開(kāi)發(fā)者,要熟練掌握語(yǔ)言最基本特性,才能開(kāi)發(fā)出最穩(wěn)健的程序。
補(bǔ)充:golang if _,ok:=range map; ok判斷key是否在map中
由于golang沒(méi)有提供item是否在array當(dāng)中的判斷方法,如果程序里面頻繁用到了這種判斷,可以將array轉(zhuǎn)化為以array當(dāng)中的成員為key的map再用上面的方法進(jìn)行判斷,這樣會(huì)提高判斷的效率。
判斷方法示例代碼
if _, ok := map[key]; ok {
//存在
}
如果每次都for循環(huán),會(huì)影響性能!
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
一文帶你了解Go語(yǔ)言中鎖特性和實(shí)現(xiàn)
Go語(yǔ)言中的sync包主要提供的對(duì)并發(fā)操作的支持,標(biāo)志性的工具有cond(條件變量)?once?(原子性)?還有?鎖,本文會(huì)主要向大家介紹Go語(yǔ)言中鎖的特性和實(shí)現(xiàn),感興趣的可以了解下2024-03-03
Go語(yǔ)言在Linux環(huán)境下輸出彩色字符的方法
這篇文章主要介紹了Go語(yǔ)言在Linux環(huán)境下輸出彩色字符的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
GO中的slice使用簡(jiǎn)介(源碼分析slice)
slice(切片)是go中常見(jiàn)和強(qiáng)大的類型,這篇文章不是slice使用簡(jiǎn)介,從源碼角度來(lái)分析slice的實(shí)現(xiàn),slice的一些迷惑的使用方式,感興趣的朋友跟隨小編一起看看吧2023-06-06
Golang實(shí)現(xiàn)http重定向https
這篇文章介紹了Golang實(shí)現(xiàn)http重定向https的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07
Go?WaitGroup及Cond底層實(shí)現(xiàn)原理
這篇文章主要為大家介紹了Go?WaitGroup及Cond底層實(shí)現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Golang的select多路復(fù)用及channel使用操作
這篇文章主要介紹了Golang的select多路復(fù)用及channel使用操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12

