You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java Stream API为列表各元素设置排序后的对应排名

Java 8 Stream实现分数排名赋值方案

你原有「先排序再遍历设置rank」的逻辑是合理的,用Stream可以更简洁地实现,根据业务常用的两种排名规则,对应实现如下:
注意:运行代码前需要先给Student类补充各属性的getter/setter方法

方案1:顺序连续排名(无并列)

排名按排序后的位置从1开始连续递增,即使分数相同也按二级排序规则区分先后,适合不需要并列排名的场景。

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("jack", 98);
        Student s2 = new Student("jason", 86);
        Student s3 = new Student("john", 80);
        List<Student> studentList = Arrays.asList(s1, s2, s3);

        List<Student> rankedList = studentList.stream()
                // 先按分数降序排序,同分可追加二级规则,比如按姓名升序
                .sorted(Comparator.comparingInt(Student::getScore).reversed()
                        .thenComparing(Student::getName))
                .collect(Collectors.toList());
        // 遍历排序后的列表按位置设rank
        IntStream.range(0, rankedList.size())
                .forEach(i -> rankedList.get(i).setRank(i + 1));
    }
}

方案2:并列跳跃排名(同分同名次)

即业务中最常用的排名规则:相同分数的学生排名一致,后续排名跳过占用的名次,比如两个98分并列第1,下一个86分就是第3名。
因为Lambda表达式要求引用的外部变量为final或等效final,这里用原子类维护遍历过程中的状态:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("jack", 98);
        Student s2 = new Student("alice", 98); // 同分测试用例
        Student s3 = new Student("jason", 86);
        Student s4 = new Student("john", 80);
        List<Student> studentList = Arrays.asList(s1, s2, s3, s4);

        // 维护三个状态:当前遍历序号、当前排名、上一个学生的分数
        AtomicInteger seq = new AtomicInteger(0);
        AtomicInteger currentRank = new AtomicInteger(1);
        AtomicInteger lastScore = new AtomicInteger(Integer.MAX_VALUE);

        List<Student> rankedList = studentList.stream()
                .sorted(Comparator.comparingInt(Student::getScore).reversed())
                .peek(stu -> {
                    int curSeq = seq.incrementAndGet();
                    // 分数和上一个不一致时,更新排名为当前序号
                    if (stu.getScore() != lastScore.get()) {
                        currentRank.set(curSeq);
                        lastScore.set(stu.getScore());
                    }
                    stu.setRank(currentRank.get());
                })
                .collect(Collectors.toList());
    }
}

补充说明

  • 如果需要实现并列连续排名(即两个98分并列第1,下一个86分是第2名),只需要调整状态逻辑:额外维护一个同分计数,分数相同时计数+1,分数变化时用当前排名 + 同分计数更新排名,同时重置计数即可。
  • 以上实现直接修改原Student对象的rank属性,如果不想改动原列表元素,可以在流的map阶段新建Student对象,拷贝属性并设置rank后返回新对象。
  • 十万级以下数据量场景下,Stream实现和普通for循环性能差异可忽略;超大数据量场景下普通for循环性能略优,可按需选择。

内容的提问来源于stack exchange,提问作者Kano2525

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:21:22