亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java模擬rank/over函數(shù)實現(xiàn)獲取分組排名的方法詳解

 更新時間:2023年04月10日 14:24:18   作者:chz613  
這篇文章主要為大家詳細介紹了Java模擬rank()、over()函數(shù)獲取分組排名的方法設(shè)計及實現(xiàn),文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下

背景

考試批次班級姓名語文
202302三年一班張小明130.00
202302三年一班王二小128.00
202302三年一班謝春花136.00
202302三年二班馮世杰129.00
202302三年二班馬功成130.00
202302三年二班魏翩翩136.00

假設(shè)我們有如上數(shù)據(jù),現(xiàn)在有一個需求需要統(tǒng)計各學(xué)生語文單科成績在班級中的排名和全年段排名,你會如何實現(xiàn)?

很容易的我們想到了 rank() over() 實現(xiàn)

over()是分析函數(shù),可以和 rank()、 dense_rank() 、 row_number() 配合使用。

使用語法如下:

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)

解釋:partition by用于給結(jié)果集分組,如果沒有指定那么它把整個結(jié)果集作為一個分組。

  • rank()涵數(shù)主要用于排序,并給出序號 ,對于排序并列的數(shù)據(jù)給予相同序號,并空出并列所占的名次。
  • dense_rank() 功能同rank()一樣,區(qū)別在于不空出并列所占的名次
  • row_number()涵數(shù)則是按照順序依次使用 ,不考慮并列

rank 結(jié)果為 1,2,2,4 dense_rank 結(jié)果為 1,2,2,3 row_number 結(jié)果為 1,2,3,4

實際應(yīng)用中,會存在數(shù)據(jù)從其他外部系統(tǒng)接入且數(shù)據(jù)量不大等多種情況,那么使用Java代碼的方式實現(xiàn)分組排名的功能則顯得更加方便。

詳細設(shè)計及實現(xiàn)

排序定義類 OrderBy

public class OrderBy {
    private String orderByEL;
    /**
     * 是否升序
     */
    private boolean ascend;

    public OrderBy(){
        //默認(rèn)升序
        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;
    }
}

該類定義了如下屬性:

  • 排序的fileld
  • 是否升序

獲取排名方法

該方法定義如下:

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

該方法提供了5個入?yún)ⅲ?/p>

dataList 排序的數(shù)據(jù)集

partitionByFields 分組field的數(shù)組

orderByList 排序字段集合

resultField 排名結(jié)果存放的字段

rankType 排名方式

  • 1:不考慮并列(row_number 結(jié)果為 1,2,3,4)
  • 2:考慮并列,空出并列所占的名次(rank 結(jié)果為 1,2,2,4)
  • 3:考慮并列,不空出并列所占的名次(dense_rank 1,2,2,3)

該方法具體實現(xiàn)如下

    public static <T> void rankOver(List<T> dataList, String[] partitionByFields, List<OrderBy> orderByList, String resultField, int rankType) {
        if (CollectionUtils.isEmpty(orderByList)) {
            return;
        }
        //STEP_01 剔除掉不參與排名的數(shù)據(jù)
        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);
                        }
                    }
                }
            }
        }
    }

使用案例

定義一個學(xué)生類:

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;
    }
}

我們寫一個方法,返回如下數(shù)據(jù):

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;
}

獲取學(xué)生語文成績的班級排名和年段排名,排名采用并列并空出并列所占用名次的方式。

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 學(xué)生:%s 語文成績:%s 班級排名:%s 全校排名:%s", s.getBanji(), s.getName(), s.getYuwen(), s.getRank2(), s.getRank1()));
    }
    log("");
}

結(jié)果如下:

語文單科成績排名情況如下:
考試批次:202302
班級:三年一班 學(xué)生:張小明 語文成績:130.0 班級排名:2 全校排名:3
班級:三年一班 學(xué)生:王二小 語文成績:128.0 班級排名:3 全校排名:6
班級:三年一班 學(xué)生:謝春花 語文成績:136.0 班級排名:1 全校排名:1
班級:三年二班 學(xué)生:馮世杰 語文成績:129.0 班級排名:3 全校排名:5
班級:三年二班 學(xué)生:馬功成 語文成績:130.0 班級排名:2 全校排名:3
班級:三年二班 學(xué)生:魏翩翩 語文成績:136.0 班級排名:1 全校排名:1

可以看到全校排名中 有兩個并列第一名 兩個并列第三名,且空出了并列所占用的名次2 和 名次4

到此這篇關(guān)于Java模擬rank/over函數(shù)實現(xiàn)獲取分組排名的方法詳解的文章就介紹到這了,更多相關(guān)Java獲取分組排名內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot讀取yml文件中的list列表、數(shù)組、map集合和對象方法實例

    springboot讀取yml文件中的list列表、數(shù)組、map集合和對象方法實例

    在平時的yml配置文件中,我們經(jīng)常使用到配置基本數(shù)據(jù)類型的字符串,下面這篇文章主要給大家介紹了關(guān)于springboot讀取yml文件中的list列表、數(shù)組、map集合和對象的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • 超詳細講解Java秒殺項目登陸模塊的實現(xiàn)

    超詳細講解Java秒殺項目登陸模塊的實現(xiàn)

    這是一個主要使用java開發(fā)的秒殺系統(tǒng),項目比較大,所以本篇只實現(xiàn)了登陸模塊,代碼非常詳盡,感興趣的朋友快來看看
    2022-03-03
  • SpringBoot發(fā)現(xiàn)最新版Druid重大問題(坑)

    SpringBoot發(fā)現(xiàn)最新版Druid重大問題(坑)

    這篇文章主要介紹了SpringBoot發(fā)現(xiàn)最新版Druid重大問題(坑),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • SpringBoot基于Minio實現(xiàn)分片上傳、斷點續(xù)傳的實現(xiàn)

    SpringBoot基于Minio實現(xiàn)分片上傳、斷點續(xù)傳的實現(xiàn)

    本文主要介紹了SpringBoot基于Minio實現(xiàn)分片上傳、斷點續(xù)傳的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • SpringBoot+MyBatisPlus中樂觀鎖的實現(xiàn)示例

    SpringBoot+MyBatisPlus中樂觀鎖的實現(xiàn)示例

    樂觀鎖是一種用于解決并發(fā)沖突的機制,在數(shù)據(jù)庫中用于保護數(shù)據(jù)的一致性,本文主要介紹了SpringBoot+MyBatisPlus中樂觀鎖的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • CompletableFuture創(chuàng)建及功能使用全面詳解

    CompletableFuture創(chuàng)建及功能使用全面詳解

    這篇文章主要為大家介紹了CompletableFuture創(chuàng)建及功能使用全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • IDEA版最新MyBatis程序配置教程詳解

    IDEA版最新MyBatis程序配置教程詳解

    這篇文章主要介紹了IDEA版最新MyBatis程序配置教程詳解,需要的朋友可以參考下
    2020-07-07
  • SpringBoot 項目添加 MDC 日志鏈路追蹤的執(zhí)行流程

    SpringBoot 項目添加 MDC 日志鏈路追蹤的執(zhí)行流程

    日志鏈路追蹤就是將一個標(biāo)志跨線程進行傳遞,在一般的小項目中也就是在你新起一個線程的時候,或者使用線程池執(zhí)行任務(wù)的時候會用到,比如追蹤一個用戶請求的完整執(zhí)行流程,本文給大家介紹SpringBoot MDC 日志鏈路追蹤的代碼,感興趣的朋友一起看看吧
    2021-06-06
  • 一篇文章帶你深入了解Java基礎(chǔ)

    一篇文章帶你深入了解Java基礎(chǔ)

    這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • java并發(fā)編程中實現(xiàn)可見性的四種可行方案解析

    java并發(fā)編程中實現(xiàn)可見性的四種可行方案解析

    這篇文章主要介紹了java并發(fā)編程中實現(xiàn)可見性的四種可行方案解析,使用關(guān)鍵字volatile和使用鎖(如synchronized關(guān)鍵字或者java.util.concurrent包中的鎖)來確保對共享變量的修改在多線程環(huán)境中能夠正確地被其他線程所觀察到,需要的朋友可以參考下
    2023-08-08

最新評論