>  기사  >  Java  >  그룹 순위를 얻기 위해 Java에서 순위/오버 함수를 시뮬레이션하는 방법

그룹 순위를 얻기 위해 Java에서 순위/오버 함수를 시뮬레이션하는 방법

WBOY
WBOY앞으로
2023-05-03 13:52:061657검색

배경

2023023년마다 3반왕중2초등학교128.002023023년 동안 3반시에 춘화136.00 2023022학년 3년Feng Shijie 129.002023023년 2반 Ma Gongcheng130.002023023학년 2반Wei Pianpian136.00위의 데이터가 있고 이제 각 학생의 중국어를 계산해야 한다고 가정합니다. 수업 중 단일 과목 점수 순위와 전체 학년 순위를 어떻게 달성할 수 있나요?
RANK() OVER(PARTITION BY COLUMN ORDER BY COLUMN)
dense_rank() OVER(PARTITION BY COLUMN ORDER BY COLUMN)
ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN)
row_number() 함수는 동점을 고려하지 않고 순서대로 사용됩니다
rank() over() 구현을 생각하면 쉽습니다. over()는 Rank(),density_rank(), row_number()와 함께 사용할 수 있는 분석 함수입니다. 사용 구문은 다음과 같습니다. 설명: partition by는 결과 집합을 그룹화하는 데 사용됩니다. 지정하지 않으면 전체 결과 집합을 그룹으로 처리합니다.
rank() 함수는 주로 정렬에 사용되며 정렬된 데이터와 병렬 데이터에 동일한 시퀀스 번호를 부여하고 병렬의 순위를 지웁니다. dense_rank()는 Rank()와 동일한 기능을 가지고 있지만, 동점이 차지한 순위는 지워지지 않는다는 차이점이 있습니다.

순위 결과 결과는 1,2,2,4density_rank이고 결과는 1,2,2,3 row_number이고 결과는 1,2,3,4입니다.

실제 응용 프로그램에서는 다음에서 액세스하는 데이터가 있습니다. 다른 외부 시스템과 데이터 양이 크지 않은 경우에는 Java 코드를 사용하여 그룹 순위 기능을 구현하는 것이 더 편리합니다. destailed 디자인 및 구현 정의 정의 클래스 주문 class
public class OrderBy {
    private String orderByEL;
    /**
     * 是否升序
     */
    private boolean ascend;

    public OrderBy(){
        //默认升序
        this.ascend = true;
    }

    public String orderByEL(){
        return this.orderByEL;
    }

    public OrderBy orderByEL(String orderByEL){
        this.orderByEL = orderByEL;
        return this;
    }

    public OrderBy ascend(boolean ascend){
        this.ascend = ascend;
        return this;
    }

    public boolean ascend(){
        return this.ascend;
    }
}

이 클래스는 다음 속성을 정의합니다. 메소드는 다음과 같이 정의됩니다.

<T> void rankOver(List<T> dataList, String[] partitionByFields, List<OrderBy> orderByList, String resultField, int rankType);

이 메소드는 5개의 입력 매개변수를 제공합니다:

    dataList 정렬된 데이터 세트
  • partitionByFields 그룹화된 필드 배열

  • orderByList 정렬 필드 컬렉션
  • resultField 필드 순위 결과가 저장됨

  • rankType 순위 메소드
  • 1: 동점을 고려하지 않음(row_number 결과는 1,2,3,4)

2: 동점을 고려하고 순위는 동점이 차지하도록 둡니다(순위 결과는 1,2,2, 4)

3: 동점이라고 생각하고 동점 순위를 빼지 마세요(dense_rank 1,2,2,3)

이 메서드의 구체적인 구현은 다음과 같습니다

    public static <T> void rankOver(List<T> dataList, String[] partitionByFields, List<OrderBy> orderByList, String resultField, int rankType) {
        if (CollectionUtils.isEmpty(orderByList)) {
            return;
        }
        //STEP_01 剔除掉不参与排名的数据
        List<T> tempList = new ArrayList<>();
        for (T data : dataList) {
            boolean part = true;
            for (OrderBy rptOrderBy : orderByList) {
                Object o1 = executeSpEL(rptOrderBy.orderByEL(), data);
                if (o1 == null) {
                    //参与排序的值为null的话则不参与排名
                    part = false;
                    break;
                }
            }
            if (part) {
                tempList.add(data);
            }
        }
        if (CollectionUtils.isEmpty(tempList)) {
            return;
        }
        //STEP_02 分组
        Map<String, List<T>> groupMap = group(tempList, null, partitionByFields);
        for (List<T> groupDataList : groupMap.values()) {
            order(orderByList, groupDataList);
            if (rankType == 1) {
                int rank = 1;
                for (T temp : groupDataList) {
                    setFieldValue(temp, resultField, rank);
                    rank++;
                }
            } else {
                int prevRank = Integer.MIN_VALUE;
                int size = groupDataList.size();
                for (int i = 0; i < size; i++) {
                    T current = groupDataList.get(i);
                    if (i == 0) {
                        //第一名
                        setFieldValue(current, resultField, 1);
                        prevRank = 1;
                    } else {
                        T prev = groupDataList.get(i - 1);
                        boolean sameRankWithPrev = true;//并列排名
                        for (OrderBy rptOrderBy : orderByList) {
                            Object o1 = executeSpEL(rptOrderBy.orderByEL(), current);
                            Object o2 = executeSpEL(rptOrderBy.orderByEL(), prev);
                            if (!o1.equals(o2)) {
                                sameRankWithPrev = false;
                                break;
                            }
                        }
                        if (sameRankWithPrev) {
                            setFieldValue(current, resultField, getFieldValue(prev, resultField));
                            if (rankType == 2) {
                                ++prevRank;
                            }
                        } else {
                            setFieldValue(current, resultField, ++prevRank);
                        }
                    }
                }
            }
        }
    }
    사용 사례
  • 정의 학생 수업:

    public class Student {
        private String batch;
        private String banji;
        private String name;
        private Double yuwen;
        //extra
        private Integer rank1;
        private Integer rank2;
        
        public Student(String batch, String banji, String name, Double yuwen) {
            this.batch = batch;
            this.banji = banji;
            this.name = name;
            this.yuwen = yuwen;
        }
    }
  • 다음 데이터를 반환하는 메소드를 작성합니다.
  • public List<Student> getDataList() {
        List<Student> dataList = new ArrayList<>();
        dataList.add(new Student("202302", "三年一班", "张小明", 130.0));
        dataList.add(new Student("202302", "三年一班", "王二小", 128.0));
        dataList.add(new Student("202302", "三年一班", "谢春花", 136.0));
        dataList.add(new Student("202302", "三年二班", "冯世杰", 129.0));
        dataList.add(new Student("202302", "三年二班", "马功成", 130.0));
        dataList.add(new Student("202302", "三年二班", "魏翩翩", 136.0));
        return dataList;
    }

    학생들의 중국어 점수의 학급 순위와 학년 순위를 구합니다. 순위는 동점을 제외하고 묶는 방식을 기반으로 합니다.

    List<Student> dataList = getDataList();
    List<OrderBy> orderByList = new ArrayList<>();
    orderByList.add(new OrderBy().orderByEL("yuwen").ascend(false));
    //获取全校排名
    DataProcessUtil.rankOver(dataList, new String[]{"batch"}, orderByList, "rank1", 2);
    //获取班级排名
    DataProcessUtil.rankOver(dataList, new String[]{"batch", "banji"}, orderByList, "rank2", 2);
    log("语文单科成绩排名情况如下:");
    
    Map<String, List<Student>> groupMap = DataProcessUtil.group(dataList, null, new String[]{"batch"});
    for (Map.Entry<String, List<Student>> entry : groupMap.entrySet()) {
        log("考试批次:" + entry.getKey());
        for (Student s : entry.getValue()) {
            log(String.format("班级:%s 学生:%s 语文成绩:%s 班级排名:%s 全校排名:%s", s.getBanji(), s.getName(), s.getYuwen(), s.getRank2(), s.getRank1()));
        }
        log("");
    }
  • 결과는 다음과 같습니다.

중국어 과목 점수 순위는 다음과 같습니다.

시험 배치: 202302

반: 1급, 3급 학생: Zhang Xiaoming 중국어 점수: 130.0 반 순위: 2 전교 순위: 3

반: 3학년 1반 학생: Wang Er Xiao 중국어 점수: 128.0 반 순위: 3 전교 순위: 6

반: 3반 학생: Feng Shijie 중국어 점수: 129.0 반 순위: 3 전교 순위: 5

반: 3학년 2학년 학생: Ma Gongcheng 중국어 성적: 130.0 반 순위: 2 전체 학교 순위: 3

반: 2학년 3학년 학생: Wei Pianpian 중국어 성적: 136.0 반 순위: 1 학교 순위: 1

학교 순위를 보면 공동 1위 2명, 공동 3위 2명이 있고, 공동 2위와 4위가 공석인 것을 볼 수 있습니다

위 내용은 그룹 순위를 얻기 위해 Java에서 순위/오버 함수를 시뮬레이션하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제