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

Scala TreeMap仅存一个元素问题求助:与Java实现结果差异

这是个很典型的TreeMap键相等性判断的坑,核心差异出在Scala TreeMap的判断逻辑,以及你写的Java Comparator的错误实现上,咱们慢慢捋清楚:

1. Scala代码的问题:排序规则直接导致键被判定为同一

Scala里的TreeMap(不管可变还是不可变),是完全依赖传入的Ordering来判断键是否相等的——只要Ordering.compare(a, b)返回0,就会把a和b当成同一个键,后续的put操作直接覆盖之前的值。

你写的Ordering.by(x => x._1)只拿元组的第一个元素做排序依据,那当两个元组的第一个元素相等时(比如(9,21)和(9,10)),compare方法会返回0,TreeMap自然就认为这俩是同一个键,第二个put直接把第一个值覆盖了,最终size就是1。

如果想让第一个元素相等时,用第二个元素区分开,得修改排序规则,比如:

// 方法1:同时把两个元素作为排序键
val a = scala.collection.mutable.TreeMap[(Int, Int), String]()(
  Ordering.by[(Int, Int), (Int, Int)](x => (x._1, x._2))
)

// 方法2:直接用元组默认的Ordering(更简洁)
val a = scala.collection.mutable.TreeMap[(Int, Int), String]()(
  Ordering.Tuple2(Ordering.Int, Ordering.Int)
)

这样修改后,两个键就会被判定为不同,最终size会变成2。

2. Java代码的“假象”:Comparator实现错误才保留了两个元素

你写的Java Comparator其实是不符合规范的,先回忆一下Comparator.compare的返回规则:

  • 返回负数:表示前者排在后者前面
  • 返回0:表示两者相等
  • 返回正数:表示前者排在后者后面

而你的实现:

@Override
public int compare(Tuple arg0, Tuple arg1) {
    if (arg0.a > arg1.a) {
        return arg0.a;
    } else return arg1.a;
}

当两个Tuple的a相等时(比如都是100),会返回arg1.a也就是100(正数),而不是规范要求的0,所以Java的TreeMap会认为这两个键不相等,因此两个元素都被保留,size是2。

如果把Java的Comparator改成正确的、只比较第一个元素的实现:

@Override
public int compare(Tuple arg0, Tuple arg1) {
    return arg0.a.compareTo(arg1.a);
}

这时候再运行,你会发现Java的TreeMap size也会变成1,和Scala之前的结果一致——因为此时两个键会被判定为相等,第二个put覆盖了第一个值。

总结一下

  • Scala的TreeMap严格遵循Ordering的结果判断键相等性,只要compare返回0就视为同一键
  • 你之前的Java代码是因为Comparator实现错误,才出现了和Scala不同的结果,并非Java和Scala的TreeMap逻辑有差异
  • 要让Scala的TreeMap保留两个元素,必须修改Ordering,让它同时比较元组的两个元素

内容的提问来源于stack exchange,提问作者Guda uma shanker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:25:34