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

如何在Kotlin流中使用sortedByDescending实现单流式处理?

Kotlin流式处理球员数据问题解答

问题背景

需求是实现球员数据的流式处理:

  • 读取标准输入中包含球员队伍、姓名、参赛场次、得分的行数据
  • 筛选出参赛场次≥15的球员
  • 按场均得分(ppg)降序排序
  • 打印排名前十的球员

已实现的Java单流方案:

// JAVA SOLUTION - WORKS
new BufferedReader(new InputStreamReader(System.in))
    .lines()
    .map(line -> line.split(","))
    .map(Player::fromLine)
    .filter(p -> p.games >= 15)
    .sorted((p1, p2) -> Double.compare(p2.ppg, p1.ppg))
    .limit(10)
    .map(Player::reportLine)
    .forEach(System.out::println);

(注:Player为自定义记录类,fromLine方法负责解析数据并计算场均得分ppg)

尝试直接转成Kotlin时遇到报错:

// KOTLIN ATTEMPT - THIS DOES NOT WORK
BufferedReader(InputStreamReader(System.`in`))
    .lines()
    .map { it.split(",") }
    .map { Player.fromLine(it) }
    .filter { it.games >= 15 }
    .sortedByDescending { it.ppg }  // ERROR ON THIS LINE
    .take(10)
    .map { it.reportLine() }
    .forEach { println(it) }

报错信息:

error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch: ...

目前通过转成List分两步实现了功能:

// KOTLIN SOLUTION - WORKS (but can it done in one shot?)
val players = BufferedReader(InputStreamReader(System.`in`))
    .lines()
    .map { it.split(",") }
    .map { Player.fromLine(it) }
    .filter { it.games >= 15 }
    .toList()

players.sortedByDescending { it.ppg }
    .take(10)
    .map { it.reportLine() }
    .forEach { println(it) }

疑问

  1. 能否将排序步骤整合进单流处理中?
  2. 为何非工作方案中filter的返回结果不是合法的可迭代对象?

解答

1. 可以整合进单流处理,两种实现方式

方式一:使用Java Stream的sorted方法传入Comparator

因为BufferedReader.lines()返回的是Java Stream,可以直接用Java Stream自带的sorted方法,传入Kotlin lambda作为Comparator:

BufferedReader(InputStreamReader(System.`in`))
    .lines()
    .map { it.split(",") }
    .map { Player.fromLine(it) }
    .filter { it.games >= 15 }
    .sorted { p1, p2 -> p2.ppg.compareTo(p1.ppg) }
    .limit(10)
    .map { it.reportLine() }
    .forEach { println(it) }

也可以用Comparator的链式写法:

BufferedReader(InputStreamReader(System.`in`))
    .lines()
    .map { it.split(",") }
    .map { Player.fromLine(it) }
    .filter { it.games >= 15 }
    .sorted(Comparator.comparingDouble<Player> { it.ppg }.reversed())
    .limit(10)
    .map { it.reportLine() }
    .forEach { println(it) }

方式二:将Java Stream转为Kotlin Sequence

通过asSequence()把Java Stream转换成Kotlin的Sequence,这样就能直接使用Kotlin的sortedByDescending扩展函数:

BufferedReader(InputStreamReader(System.`in`))
    .lines()
    .asSequence()  // 转换为Kotlin Sequence
    .map { it.split(",") }
    .map { Player.fromLine(it) }
    .filter { it.games >= 15 }
    .sortedByDescending { it.ppg }
    .take(10)
    .map { it.reportLine() }
    .forEach { println(it) }

2. 关于filter返回结果的类型问题

BufferedReader.lines()返回的是java.util.stream.Stream(Java标准库的流类型),它的filter方法返回的依然是Java Stream,而不是Kotlin的Iterable或Sequence类型。

Kotlin的sortedByDescending是Kotlin标准库专门为Iterable、Sequence等Kotlin原生集合/序列类型提供的扩展函数,Java Stream并不属于这些类型体系,因此无法直接调用该方法,这就是报错的核心原因。

当你调用toList()后,得到的是Kotlin的List(属于Iterable接口),自然就能使用sortedByDescending这类扩展函数了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 06:55:53