ホームページ  >  記事  >  Java  >  Javaでランク/オーバー関数をシミュレートしてグループランキングを取得する方法

Javaでランク/オーバー関数をシミュレートしてグループランキングを取得する方法

WBOY
WBOY転載
2023-05-03 13:52:061653ブラウズ

背景

202302クラス 3 年张小明130.00202302三クラス 1毎年##128.00##3年クラス1#謝春華馮世傑马 Gongchengウェイ ピアンピアン 上記のデータがあり、次があると仮定します。各生徒の中国語のシートを数える必要があります。クラス内での科目の得点の順位と、年間全体の順位をどのように達成しますか? rank() over()の実装を考えるのは簡単です。over() は、rank()、dense_rank() と組み合わせて使用​​できる分析関数です。 、および row_number()。
検査バッチ クラス 名前 中文
##王二小 202302
136.00 202302 三级二级
129.00 202302 3 年 2 組
130.00 202302 クラス 2、グレード 3
136.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)

説明: 結果セットをグループ化するために、partition by が使用されます。指定しない場合、結果セット全体がグループとして扱われます。

Rank()関数は主にソートに使用され、シーケンス番号を付与する関数で、ソートされた並列データに同じシーケンス番号が付与され、同順位の順位がクリアされます。

    dense_rank() は、rank() と同じ関数を持ちます。違いは、同順位の順位が空にされないことです。
  • row_number( ) 関数は、並列処理に関係なく、順番に使用されます。
  • rank 結果は 1,2,2,4 になります。dens_rank 結果は、1,2,2,3 row_number になります。結果は、 1,2 ,3,4

  • となります。実際のアプリケーションでは、他の外部システムからデータにアクセスする場面が多く、データ量がそれほど多くないため、さらに多くなります。グループのランキングを達成するには Java コードを使用することが重要です。便利です。
詳細な設計と実装

ソート定義クラス OrderBy
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;
    }
}

このクラスは次の属性を定義します:

sorted fileld

    昇順かどうか
  • ランキングメソッドの取得
  • このメソッドは次のように定義されています:

    <T> void rankOver(List<T> dataList, String[] partitionByFields, List<OrderBy> orderByList, String resultField, int rankType);
  • このメソッドは 5 つの入力パラメータを提供します。

dataList 並べ替えられたデータ セット

partitionByFields グループ化フィールドの配列

orderByList 並べ替えフィールド コレクション

resultField ランキング結果が含まれるフィールドstorage

#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

クラス: 3 年 1 組生徒: Zhang Xiaoming 中国語スコア: 130.0 クラスランク: 2 学校ランキング: 3

クラス: Class 1, Grade 3 学生: Wang Er Xiao 中国語スコア: 128.0 クラスランク: 3 学校ランキング: 6

クラス: Class 3, 3 年生: Xie Chunhua 中国語スコア: 136.0 クラス ランク: 1 学校ランキング: 1

クラス: Grade 2 3 年生: Feng Shijie 中国語スコア: 129.0 クラス ランク: 3 学校ランキング: 5
クラス: 学年3 年生 2 人: Ma Gongcheng 中国語スコア: 130.0 クラス ランク: 2 学校ランキング: 3

クラス: Grade 2 クラス 3 生徒: Wei Pianpian 中国語スコア: 136.0 クラス ランク: 1 学校ランキング: 1


学校ランキングには 2 つあることがわかります。1 位に 2 つと 3 位に 2 つが同点で、同点の 2 位と 4
# は空席のままです。

以上がJavaでランク/オーバー関数をシミュレートしてグループランキングを取得する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。