使用一个字段实现第二条件排序

· · 967 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

在排序中,经常遇到变量相同情况下的排序问题。在MySQL中可以使用 ORDER BY 约束多个字段。但是在redis中,使用sorted set排序时,score只能设置一个变量。这样在score相同时,只能使用字典序了(这个是从文档上看到的,具体没验证)
这就会出现一些问题了,最简单,在游戏排行榜中,我原来是排第一的,突然来了个人,分数和我相同,但是排到我前面了,我成第二了,玩家肯定不干了。但是redis只能使用一个值作为排序条件,这就需要我们在一个值里既能记录原有的分数,还要记录另一个值。
比较常见的是用时间作为第二个排序条件,谁先达到这个分数,谁排在前面。
要实现这个功能,要满足 可逆稳定排序 两个要求。

  1. 可逆:把数值处理后还能到的原来的值(分数和时间)
  2. 稳定排序:添加时间后不能影响原来的排序结果,添加的时间只是在分数相同的情况下才起作用

简单的对数值进行加减乘除是没法实现的了,简单的数值加减乘除一是不能恢复原来的数据,二是会影响到原有的排序。

不卖关子了,使用‘或’运算,可以实现这个需求。把两个数值进行运算,生成一个数。简单说一下原理。
运算的规则是在二进制位上,有1 或 运算后还是1,两个都是0 或运算后是 0。 例:1或2 二进制表示 01|10 = 11。但是现在却发现,无法实现数据还原,这就需要移位了。就是两个8位长的数据,或 运算后要成为16位的数据。
还是上个例子:为了简单起见,假设原数据是2位长,先把原来2位长的数据转成4位长,然后左移2位,1就从原来的01变成了0111。2只变成4位,不移位。2从10变成0010。0100|0010 = 0110。这样就能还原数据了。前两位01是原来的1,后两位10就是原来的2。
下面通过代码来实现一下。
代码用golang实现

package main

import (
    "fmt"
    "math/rand"
    "sort"
)

func main() {
    arr := make([]uint64, 10)
    b := rand.Perm(10)
    for i := 0; i < 10; i++ {
        var a uint32
        if i%2 == 0 {
            a = 10
        } else {
            a = 5
        }
        arr[i] = uint64(a)<<32 | uint64(b[i])
        fmt.Println(a, b[i], arr[i])
    }
    sort.Sort(Myuint64(arr))

    fmt.Println("排序后")
    for _, v := range arr {
        fmt.Println(v, v>>32, uint32(v))
    }
}

type Myuint64 []uint64

func (this Myuint64) Len() int {
    return len(this)
}
func (this Myuint64) Less(i, j int) bool {
    return this[i] > this[j]
}

func (this Myuint64) Swap(i, j int) {
    this[i], this[j] = this[j], this[i]
}

简单说一下代码,第一排序条件用了间隔使用了5和是这两个数,第二条件随机生成了10个不重复的随机数,不用时间戳的原因是,程序运行的时间很短,取到的时间戳基本是一个数,看不出区别,本质思想都是一样的。排序使用了go自带的排序接口,不了解的看一下上篇文章,传送门代码中fmt.Println(v, v>>32, uint32(v)) 就是解数据, 运算后,前32位是一个数,后32位是另一个数据。取前面的数据只需要把计算后的数据右移32位就行了,取后面的数据,更简单了,直接强转成32位的类型就行了。
看一下运行结果:


可以看到,排序前,10和5交替出现,第二条件没有规律
排序后,先使用第一个数排序,第一个数相同时,使用第二条件排序。而且我们也成功还原了原来的数据。
好了,这样就实现了用一个数值实现第二条件排序了。在存入redis时只需要把计算后的数据存入redis就行了,显示数据的时候,只需要解一下数据就行了。
好了,到这就介绍完了,有问题欢迎评论区讨论


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:

查看原文:使用一个字段实现第二条件排序

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

967 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传