为什么不可变版的ListMap存储升序,而可变版本按降序存储?
这是一个测试,您可以使用,如果你有scalatest-1.6.1.jar和junit-4.9.jar
@Test def StackoverflowQuestion() { val map = Map("A" -> 5,"B" -> 12,"C" -> 2,"D" -> 9,"E" -> 18) val sortedIMMUTABLEMap = collection.immutable.ListMap[String,Int](map.toList.sortBy[Int](_._2): _*) println("head : " + sortedIMMUTABLEMap.head._2) println("last : " + sortedIMMUTABLEMap.last._2) sortedIMMUTABLEMap.foreach(X => println(X)) assert(sortedIMMUTABLEMap.head._2 < sortedIMMUTABLEMap.last._2) val sortedMUTABLEMap = collection.mutable.ListMap[String,Int](map.toList.sortBy[Int](_._2): _*) println("head : " + sortedMUTABLEMap.head._2) println("last : " + sortedMUTABLEMap.last._2) sortedMUTABLEMap.foreach(X => println(X)) assert(sortedMUTABLEMap.head._2 > sortedMUTABLEMap.last._2) }
接受PASSING测试的输出:
head : 2 last : 18 (C,2) (A,5) (D,9) (B,12) (E,18) head : 18 last : 2 (E,18) (B,12) (D,9) (A,5) (C,2)
解决方法
症状可以简化为:
scala> collection.mutable.ListMap(1 -> "one",2 -> "two").foreach(println) (2,two) (1,one) scala> collection.immutable.ListMap(1 -> "one",2 -> "two").foreach(println) (1,one) (2,two)
您的代码中的“排序”不是问题的核心,您对ListMap的调用是使用来自构造由可变或不可变列表支持的列表映射的协同对象的ListMap.apply调用.规则是插入顺序将被保留.
差异似乎是可变列表由不可变列表支持,插入发生在前面.所以这就是为什么当迭代你得到LIFO行为.我还在看着这个不变的,但是我敢打赌,这些插入是有效的在后面.编辑,我改变主意:insert可能在前面,但似乎immutable.ListMap.iterator方法决定在返回的迭代器上使用一个toList.reverseIterator来反转结果.我认为它值得把它放在邮件列表中.
文件可以更好吗?当然.有疼吗不是真的,我不会让它发生.如果文档不完整,在选择结构与另一个结构之前,测试行为或去查找源是明智的.
实际上,如果Scala团队决定在以后改变行为,感觉可以因为行为无效,没有合同,那么可能会有痛苦.
为了解决您在评论中解释的用例,您已经收集了地图中的字符串频率计数(可变或不可变):
val map = Map("A" -> 5,"E" -> 18,"B" -> 5)
由于您最终只需要排序一次,所以您可以将元组从地图转换为seq,然后排序:
map.toSeq.sortBy(_._2) // Seq[(java.lang.String,Int)] = ArrayBuffer((C,2),(A,5),(B,(D,9),(E,18))