7

SpringBoot进阶教程(七十六)多维度排序查询 - 请叫我头头哥

 1 year ago
source link: https://www.cnblogs.com/toutou/p/springboot_sort.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
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<User> getTestUserList() {
        List<User> 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 leftList<rightList返回-1;leftList=rightList返回0;leftList>rightList返回1;
     */
    public static int compareBigDecimalList(List<BigDecimal> left, List<BigDecimal> 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<User> sortUserList(int cityId, int provinceId) {
        // 获取初始化测试list数据
        List<User> list = User.getTestUserList();
        if(list == null || list.size() == 0){
            return list;
        }

        List<ImmutablePair<User, List<BigDecimal>>> userAndScore = new ArrayList<>();
        for (User user : list){
            // 初始化一个排序的分值list
            List<BigDecimal> 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

您可以考虑给头头来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx.

支付宝打赏

支付宝账号 datou431@qq.com

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK