2011-09-24 31 views
9

为什么ListMap的不可变版本以升序存储,而可变版本以降序存储?为什么可变和不可变ListMaps在Scala中有不同的顺序?

下面是测试如果你有,你可以使用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) 
    } 

继承人的通过测试输出:

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) 
+2

良好的集合API的一个主要优点是,它保护你从不必“详尽了解所有像偏心这个”。迭代的顺序不是'ListMap'的合约的一部分,所以你不必考虑它。 –

+0

不太具体的界面描述为未来的变更/改进留下了更多空间。如果你想要元素顺序的可靠行为,请使用'SortedMap'。 – Raphael

+0

感谢排序地图对我有好处。 – Zasz

回答

12

症状可以简化为:

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行为。我仍然看着不可改变的那个,但我敢打赌,这些插入效果在后面。编辑,我改变了主意:插入可能在前面,但看起来immutable.ListMap.iterator方法决定在返回的迭代器上将结果与toList.reverseIterator相反。我认为它值得把它列入邮件列表。

文档可以更好吗?当然。有疼痛吗?不是,我不会让它发生。如果文档不完整,那么在测试结构之前或者在选择结构之前查看源代码是比较明智​​的。

事实上,如果斯卡拉团队决定在以后改变行为,并感觉他们可以,那么可能会很痛苦,因为这种行为实际上是无证的,没有合同。


为了满足您的使用情况下,在注释解释,说你已经收集在一个地图串频数(可变或不变):

val map = Map("A" -> 5, "B" -> 12, "C" -> 2, "D" -> 9, "E" -> 18, "B" -> 5) 

既然你只需要一次排序在结束时,可以从地图转换的元组为seq,然后排序:

map.toSeq.sortBy(_._2) 
// Seq[(java.lang.String, Int)] = ArrayBuffer((C,2), (A,5), (B,5), (D,9), (E,18)) 
+0

好点,如果他们现在(或者以后)改变了一些东西,会有点问题。我发现它很难调试,因为我的排序测试和源代码具有完全相同的代码,但ListMap版本不同。如果集合有更好的名称来表示它们的可变性,那么它会好得多 – Zasz

+0

如果你可以建议我应该使用哪种数据结构,我将把这个答案标记为正确的,我需要一个按int值排序的(string,int)和排序后的ITERABLE。 – Zasz

+0

@Zasz,你允许在你的表中使用同一个int的重复或多个字符串吗?你需要该表保持排序,因为它是变异的?或者如果你在显示/迭代之前对它进行排序,那很好吗?我不接受我的答案,直到我从邮件列表中收到回复... – huynhjl

4

在我看来既不ListMap声称自己是一个有序映射,只是地图用List实现。事实上,我没有看到他们合同中的任何内容说明有关保留广告订单的任何内容。

Scala中的编程解释说,如果早期元素更可能被访问,那么它可能是有用的,但否则它与Map没有多大优势。

+1

正是我的意思是没有足够的数据结构信息。在我看到一个在stackoverflow中的线程后,如何选择ListMap,用它来进行排序。根据为ListMap文档编写的内容,知道在哪里使用ListMap是非常困难的 – Zasz

1

不要对订单产生任何期望,它没有声明,并且在Scala版本之间会有所不同。

例如:

import scala.collection.mutable.{ListMap => MutableListMap} 

MutableListMap("A" -> 5, "B" -> 12, "C" -> 2, "D" -> 9, "E" -> 18).foreach(println) 

在2.9。1给出: (E,18) (d,9) (C,2) (B,12) (A,5)

但2.11.6给出: (E,18) (C,2) (A,5) (B,12) (d,9)

相关问题