1. 程式人生 > 資料庫 >java-redis排行榜value+time排序

java-redis排行榜value+time排序

本文預覽

需求

做一個送花排行榜

  • 根據玩家送花數量倒敘排列
  • 送花數量相同時,先送花的在前面

思路

用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小)在前

完全滿足需要