• SpringBoot进阶教程(七十六)多维度排序查询


    v博客前言

    在项目中经常能遇到,需要对某些数据集合进行多维度排序的需求。对于集合多条件排序解决方案也有很多,今天我们就介绍一种,思路大致是设置一个分值的集合,这个分值是按照需求来设定大小的,再根据分值的大小对集合排序。

    v需求背景

    我们来模拟一个需求,现在需要查询一个用户列表,该列表需要实现的排序优先级如下:

    • 付费用户排在前,非付费用户排在后
    • 付费用户中,排序优先级:同城市的>同省的>等级高的>活跃用户>不活跃用户>其他用户
    • 非付费用户中,排序优先级:等级高的>同城市的>其他用户

    v代码实现

    创建user类
    复制代码
    package com.user;
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Author toutou
     * @Date 2023/2/18
     * @Des
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    public class User {
        private Integer id;
    
        /**
         * 等级
         */
        private int grade;
    
        /**
         * 所在省份id
         */
        private int provinceId;
    
        /**
         * 所在城市ID
         */
        private int cityId;
    
        /**
         * 是否是活跃用户,true活跃,false不活跃
         */
        private boolean lively;
    
        /**
         * 是否开通支付,true开通,false未开通
         */
        private boolean pay;
    
        public static List getTestUserList() {
            List list = new ArrayList<>();
            list.add(User.builder().id(0).grade(1).provinceId(1).cityId(22).lively(false).pay(false).build());
            list.add(User.builder().id(1).grade(1).provinceId(1).cityId(100).lively(true).pay(true).build());
            list.add(User.builder().id(2).grade(3).provinceId(5).cityId(100).lively(true).pay(true).build());
            list.add(User.builder().id(3).grade(2).provinceId(1).cityId(98).lively(true).pay(true).build());
            list.add(User.builder().id(4).grade(2).provinceId(1).cityId(100).lively(true).pay(true).build());
            list.add(User.builder().id(5).grade(2).provinceId(3).cityId(100).lively(true).pay(true).build());
            list.add(User.builder().id(6).grade(2).provinceId(1).cityId(101).lively(true).pay(false).build());
            list.add(User.builder().id(7).grade(1).provinceId(6).cityId(100).lively(false).pay(true).build());
            list.add(User.builder().id(8).grade(1).provinceId(1).cityId(98).lively(true).pay(false).build());
            list.add(User.builder().id(9).grade(1).provinceId(5).cityId(100).lively(true).pay(true).build());
            return list;
        }
    }
    复制代码

    为了便于调试,我们在user类中创建一个测试方法getTestUserList,以此来生成测试数据。

    创建排序帮助类
    复制代码
    package com.util;
    
    import java.math.BigDecimal;
    import java.util.List;
    
    /**
     * @Author toutou
     * @Date 2023/2/18
     * @Des
     */
    public class SortHelper {
        /**
         * 比较两个BigDecimal集合
         * @param left
         * @param right
         * @return leftListrightList返回1;
         */
        public static int compareBigDecimalList(List left, List right) {
            int length = Math.max(left.size(), right.size());
            for (int i = 0; i < length; i++) {
                if (left.size() < i + 1) {
                    return -1;
                }
                if (right.size() < i + 1) {
                    return 1;
                }
    
                int value = left.get(i).compareTo(right.get(i));
                if (value != 0) {
                    return value;
                }
            }
            return 0;
        }
    }
    复制代码
    排序实现类
    复制代码
    package com.util;
    
    import com.user.User;
    import org.apache.commons.lang3.tuple.ImmutablePair;
    
    import java.math.BigDecimal;
    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.List;
    import java.util.stream.Collectors;
    
    import reactor.core.publisher.Flux;
    
    /**
     * @Author toutou
     * @Date 2023/2/18
     * @Des
     */
    public class Sort {
        /**
         * 当前用户所在城市id,所在省份id
         * @param cityId
         * @param provinceId
         * @return
         */
        public List sortUserList(int cityId, int provinceId) {
            // 获取初始化测试list数据
            List list = User.getTestUserList();
            if(list == null || list.size() == 0){
                return list;
            }
    
            List>> userAndScore = new ArrayList<>();
            for (User user : list){
                // 初始化一个排序的分值list
                List scoreList = Flux.range(0, 6).map(p -> BigDecimal.ZERO).collectList().block();
                userAndScore.add(new ImmutablePair<>(user, scoreList));
                if(user.isPay()){
                    // 付费用户排序,付费用户为1,非付费用户为2
                    scoreList.set(0, BigDecimal.valueOf(1));
    
                    if(user.getCityId() == cityId){
                        scoreList.set(1, BigDecimal.valueOf(1));
                    }else{
                        scoreList.set(1, BigDecimal.valueOf(2));
                    }
    
                    if(user.getProvinceId() == provinceId){
                        scoreList.set(2, BigDecimal.valueOf(1));
                    }else{
                        scoreList.set(2, BigDecimal.valueOf(2));
                    }
    
                    scoreList.set(3, BigDecimal.valueOf(-user.getGrade()));
                    if(user.isLively()){
                        scoreList.set(4, BigDecimal.valueOf(1));
                    }else{
                        scoreList.set(4, BigDecimal.valueOf(2));
                    }
    
                    scoreList.set(5, BigDecimal.valueOf(-user.getId()));
                }else{
                    scoreList.set(0, BigDecimal.valueOf(2));
                    scoreList.set(1, BigDecimal.valueOf(-user.getGrade()));
                    if(user.getCityId() == cityId){
                        scoreList.set(2, BigDecimal.valueOf(1));
                    }else{
                        scoreList.set(2, BigDecimal.valueOf(2));
                    }
    
                    scoreList.set(3, BigDecimal.valueOf(-user.getId()));
                }
            }
    
            return userAndScore.stream().sorted(Comparator.comparing(p -> p.getValue(), SortHelper::compareBigDecimalList)).map(ImmutablePair::getLeft).collect(Collectors.toList());
        }
    }
    复制代码
    debug效果

    请叫我头头哥

    v源码地址

    https://github.com/toutouge/javademosecond/tree/master/hellolearn


    作  者:请叫我头头哥
    出  处:http://www.cnblogs.com/toutou/
    关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!
    版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信
    声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

  • 相关阅读:
    Reactor 第十一篇 WebFlux集成Redis
    在keil MDK中定义非初始化(noini)变量
    windows远程桌面登录ubuntu,黑屏闪退,
    计算机毕业设计选题推荐-个人健康微信小程序/安卓APP-项目实战
    计算机毕业设计Java幼儿校园通系统的设计与实现(系统+程序+mysql数据库+Lw文档)
    【AI视野·今日CV 计算机视觉论文速览 第266期】Thu, 12 Oct 2023
    25.2 MySQL 运算符
    shell中通配符的使用
    前端使用 Konva 实现可视化设计器(14)- 折线 - 最优路径应用【代码篇】
    发送自定义广播
  • 原文地址:https://www.cnblogs.com/toutou/p/springboot_sort.html