本文预览
需求
做一个送花排行榜
- 根据玩家送花数量倒叙排列
- 送花数量相同时,先送花的在前面
思路
用redis存取数据,自动维护有序集合 。
但值一样时,无法保证谁在前谁在后。所以可以把存入的时间考虑进去。
这样排序就变成了: 数值 + 时间。
因为送花数量是整数,那能不能把时间变成小数加在后面呢,这样取数据的时候,直接取整就是原始数据了。
公式:newValue = value + 1 - time / Math.pow(10, (int) Math.log10(time) + 1d)
value原始数据,time是存入时间毫秒数,newValue存入redis中的数据
newValue整数部分等于value
极值大:value大&time小。
两个玩家value值一样,先进榜(time小)的应该在前面。
代码
public class RankWithTime {
// 玩家类
static class Player {
String name;
int value;
double saveTime;
public Player(String name, int value) {
this.name = name;
this.value = value;
}
public void setSaveTime(double saveTime) {
this.saveTime = saveTime;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Player{" +
"name='" + name + '\'' +
", value=" + value +
", saveTime=" + saveTime +
'}';
}
}
// 数据存储部分 启动类redis作用
static class Redis {
private static Redis INSTANCE;
private Redis() {}
public static Redis getInstance() {
if (INSTANCE == null) {
INSTANCE = new Redis();
}
return INSTANCE;
}
/**
* 假设这是redis中保存的数据,这里没有顺序要求
*/
private Map<String, Double> dbData = new HashMap<>();
/**
* 向redis中存入数据
* 保存的是经过处理之后的数据
* @param key
* @param value
*/
public long put(String key, int value) {
long time = System.currentTimeMillis();
double dValue = value + 1 - time / Math.pow(10, (int) Math.log10(time) + 1d);
dbData.put(key, dValue);
return time;
}
/**
* 获取数据 升序
* @return ArrayList
*/
public List<Map.Entry<String, Double>> getListAsc() {
return dbData.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue)).collect(Collectors.toList());
}
/**
* 获取数据 降序
* @return ArrayList
*/
public List<Map.Entry<String, Double>> getListDesc() {
return dbData.entrySet().stream().
sorted((o1, o2) -> (int) (o2.getValue() - o1.getValue())).collect(Collectors.toList());
}
/**
* 获取数据 升序
* @return Map
*/
public Map<String, Double> getMapAsc() {
// HashMap
Map<String, Double> hashMap = dbData.entrySet().stream()
.sorted((o1, o2) -> (int) (o1.getValue() - o2.getValue()))
.collect(Collectors.toMap(o -> o.getKey(), o -> o.getValue(), (oldVal, newVal) -> newVal));
// LinkedHashMap 有序的
Map<String, Double> linkedHashMap = dbData.entrySet()
.stream()
.sorted((o1, o2) -> (int) (o1.getValue() - o2.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> newVal, LinkedHashMap::new));
return linkedHashMap;
}
/**
* 获取数据 降序
* @return LinkedHashMap
*/
public Map<String, Double> getMapDesc() {
return dbData.entrySet()
.stream()
.sorted((o1, o2) -> (int) (o2.getValue() - o1.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> newVal, LinkedHashMap::new));
}
}
public static void main(String[] args) {
// 创建 redis
final Redis redis = Redis.getInstance();
// 值相同 时间不同 结论:时间小的在前
int value = 100;
List<Player> players = new ArrayList<>();
players.add(new Player("玩家1", value));
players.add(new Player("玩家2", value + 1));
players.add(new Player("玩家3", value));
// 存数据
players.forEach(player -> {
long putTime = redis.put(player.getName(), player.getValue());
player.setSaveTime(putTime);
System.out.println("存入数据顺序 === " + player);
// 延迟
try {
Thread.sleep(1L);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 取数据 降序
List<Map.Entry<String, Double>> listAsc = redis.getListDesc();
listAsc.forEach(entry -> System.out.println("取出数据顺序 === " + new Player(entry.getKey(), entry.getValue().intValue())));
}
/*
存入数据顺序 === Player{name='玩家1', value=100, saveTime=1.610187990435E12}
存入数据顺序 === Player{name='玩家2', value=101, saveTime=1.610187990441E12}
存入数据顺序 === Player{name='玩家3', value=100, saveTime=1.610187990442E12}
取出数据顺序 === Player{name='玩家2', value=101, saveTime=0.0}
取出数据顺序 === Player{name='玩家1', value=100, saveTime=0.0}
取出数据顺序 === Player{name='玩家3', value=100, saveTime=0.0}
*/
}
总结
对照输出结果来看:
- value不同,value大的在前
- value相同,先来的(time小)在前
完全满足需要