最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

背景

考試批次班級姓名語文
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)分組排名的功能則顯得更加方便。

詳細(xì)設(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)文章

  • MyBatis實現(xiàn)多表聯(lián)查的詳細(xì)代碼

    MyBatis實現(xiàn)多表聯(lián)查的詳細(xì)代碼

    這篇文章主要介紹了MyBatis如何實現(xiàn)多表聯(lián)查,通過實例代碼給大家介紹使用映射配置文件實現(xiàn)多表聯(lián)查,使用注解的方式實現(xiàn)多表聯(lián)查,需要的朋友可以參考下
    2022-08-08
  • Java框架Quartz中的Trigger簡析

    Java框架Quartz中的Trigger簡析

    這篇文章主要介紹了Java框架Quartz中的Trigger簡析,所有類型的trigger都有TriggerKey這個屬性,表示trigger的身份;除此之外,trigger還有很多其它的公共屬性,這些屬性,在構(gòu)建trigger的時候可以通過TriggerBuilder設(shè)置,需要的朋友可以參考下
    2023-11-11
  • JAVA學(xué)習(xí)之一步步搭建spring框架

    JAVA學(xué)習(xí)之一步步搭建spring框架

    這篇文章主要介紹了JAVA學(xué)習(xí)之一步步搭建spring框架,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • SpringBoot與rabbitmq的結(jié)合的示例

    SpringBoot與rabbitmq的結(jié)合的示例

    這篇文章主要介紹了SpringBoot與rabbitmq的結(jié)合的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • mybatis中mapper-locations的作用

    mybatis中mapper-locations的作用

    這篇文章主要介紹了mybatis中mapper-locations的具體作用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • springboot?集成activemq項目配置方法

    springboot?集成activemq項目配置方法

    這篇文章主要介紹了springboot?集成activemq項目配置方法,e-car項目配置通過引入activemq依賴,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • 本地編譯打包項目部署到服務(wù)器并且啟動方式

    本地編譯打包項目部署到服務(wù)器并且啟動方式

    這篇文章主要介紹了本地編譯打包項目部署到服務(wù)器并且啟動方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 使用ByteArrayOutputStream寫入字符串方式

    使用ByteArrayOutputStream寫入字符串方式

    這篇文章主要介紹了使用ByteArrayOutputStream寫入字符串方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • spring boot使用sharding jdbc的配置方式

    spring boot使用sharding jdbc的配置方式

    這篇文章主要介紹了spring boot使用sharding jdbc的配置方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • SpringBoot使用Nacos進(jìn)行application.yml配置管理詳解

    SpringBoot使用Nacos進(jìn)行application.yml配置管理詳解

    Nacos是阿里巴巴開源的一個微服務(wù)配置管理和服務(wù)發(fā)現(xiàn)的解決方案,下面我們來看看在SpringBoot中如何使用Nacos進(jìn)行application.yml配置管理吧
    2025-03-03

最新評論

万全县| 中宁县| 江津市| 邮箱| 洞头县| 岳阳县| 潼南县| 忻城县| 区。| 同江市| 丹棱县| 伽师县| 皮山县| 平遥县| 曲水县| 靖远县| 旅游| 于田县| 浦北县| 万荣县| 吐鲁番市| 安多县| 宜阳县| 五常市| 蒲江县| 庄河市| 辉县市| 平陆县| 古丈县| 阿拉善右旗| 山东省| 陆良县| 阿尔山市| 华蓥市| 闻喜县| 招远市| 隆回县| 天水市| 贡山| 白城市| 浦城县|