教你用一個整數存儲每月打卡記錄


需求

有個需求,要存儲當月的所有打卡記錄,日歷

比如以下是我的打卡記錄

對應到JSON的數據是這樣的

{
    "day1":1,
    "day2":1,
    "day3":0,
    "day4":1,
    "day5":0,
    "day6":0,
    "day7":1,
    "day8":0,
    "day9":0,
    "day10":1,
    "day11":0,
    "day12":0,
    "day13":1,
    "day14":0,
    "day15":1,
    "day16":0,
    "day17":1,
    "day18":0,
    "day19":0,
    "day20":0,
    "day21":0,
    "day22":0,
    "day23":0,
    "day24":0,
    "day25":0,
    "day26":0,
    "day27":0,
    "day28":1,
    "day29":0,
    "day30":0,
    "day31":0
}

1代表打卡,0代表沒打卡

常規思路

建立31個字段,存儲每天的打卡記錄,在數據庫中是這樣的,打卡的天就存儲為1。

比如如下的表

這樣的實現主要有以下缺點

  1. 浪費空間。只是為了存儲一個0和1,建立了31個字段
  2. 不利於擴展。如果要追加打卡記錄,得追加字段

高級思路

我們知道二進制只有0和1,非常適合這樣的場景,只用一個32位的整型的數字,就可以存儲上面這個31天的所有打卡

用二進制數表現是這樣的

1101001001001010100000000001000

對應到二進制的整數是1764048904

也就是說,其實我們只需要用一個二進制的數字,就可以表示31天的打卡狀態

所以,我們需要一個這樣的功能

  1. 傳遞一個月的打卡狀態,返回一個對應的整數
  2. 傳遞一個整數,返回一個月的打卡狀態

Go語言實現

//簽到列表-->整數
func GetNumByList(list []int, max int) int {
    n := 0
    for i := 0; i < max; i++ {
        if list[i] == 1 {
            //將指定的二進制位設置為1
            n = n | (1 << i)
        }
    }
    return n
}

//整數-->簽到列表
func GetListByNum(n int, max int) []int {
    res := make([]int, max)
    for i := 0; i < max; i++ {
        if n&(1<<i) == (1 << i) {
            //二進制位為1的設置已打卡
            res[i] = 1
        }
    }
    return res
}

我們來測試一下

func main() {
    max := 31
    list := []int{1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}
    fmt.Println("原始打卡記錄:")
    fmt.Println(list)

    fmt.Println("打卡記錄轉數字:")
    num := GetNumByList(list, max)

    fmt.Println(num)

    fmt.Println("數字還原打卡記錄:")
    fmt.Println(GetListByNum(num, max))

}

運行后的結果輸出

這樣,我們就非常地方便用一個字段存儲了所有的打卡狀態。

這里主要用到了位運算,下面貼上GO語言的位操作

<< [ 左移 ]
1 << 2 == 4
輸出 0100 ,相比右移更常見,移位后空缺的部分全部填0
>> [ 右移 ]
10 >> 2 == 2
輸出 0010
x ^ y [ 異或 ]
10 ^ 2 == 8
操作的結果是如果某位不同則該位為1, 否則該位為0
x | y [ 或 ]
10 | 2 == 10
兩個相應的二進位中只要有一個為1, 該位的結果值為1
x & y [ 與 ]
10 & 2 == 2
兩個相應的二進位都為1, 該位的結果值才為1,否則為0
^x [ 取反 ]
^2 == -3
減1取反 補碼

思路延伸

這樣的思路可以應用在需要存儲選中狀態的需求中
比如我剛接到一個這樣的需求,直播抽獎功能,需要存儲獎品類型

像這樣的場景就非常適合用一個字段存儲所有的選中狀態,並且當獎品類型添加的時候,還有很好的擴展性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM