为什么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)
答案 0 :(得分: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
调用,该对象构造由可变或不可变的备份的列表映射名单。规则是将保留插入顺序。
差异似乎是可变列表由 immutable 列表支持,插入发生在前面。这就是为什么在迭代时你会得到LIFO行为。我仍然在看不可变的那个,但我敢打赌插入有效地在后面。编辑,我正在改变我的想法:插入可能在前面,但似乎immutable.ListMap.iterator
方法决定在返回的迭代器上用toList.reverseIterator
反转结果。我认为值得把它带到邮件列表中。
文档可以更好吗?当然。有痛苦吗?不是真的,我不会让它发生。如果文档不完整,那么在选择结构与另一个结构之前测试行为或查看源代码是明智的。
实际上,如果Scala团队决定稍后改变行为并认为他们可以,因为行为实际上没有记录并且没有合同,那么可能会有痛苦。
要解决评论中解释的用例,请说你已经在地图中收集了字符串频率计数(可变或不可变):
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))
答案 1 :(得分:4)
我认为ListMap
声称它不是一个有序地图,只是一个用List实现的地图。事实上,我在合同中没有看到任何关于保留插入顺序的内容。
Scala中的编程解释说,如果更有可能访问早期元素,ListMap可能会有用,但除此之外它没有Map优势。
答案 2 :(得分:1)
不要对订单构建任何期望,它不会被声明,并且在Scala版本之间会有所不同。
例如:
Sub LoopThroughDirectory()
Dim MyFile As String
Dim erow
Dim Filepath As String
Dim targetWbk As Workbook
Dim sourceWbk As Workbook
Filepath = "C:\test"
MyFile = Dir(Filepath)
Workbooks.Open (Filepath & "\workbook.xlsm")
Set sourceWbk = ActiveWorkbook
Do While Len(MyFile) > 0
If Not MyFile = "workbook.xlsm" And MyFile = "*.xls*" Then
Workbooks.Open (Filepath & MyFile)
Set sourceWbk = ActiveWorkbook
sourceWbk.Sheets("Sheet2").Range("A1:N24").Copy
If targetWbk.Sheets("Sheet1").Range("A1") = vbNullString Then
targetWbk.Sheets("Sheet1").Range("A1:N24").PasteSpecial xlPasteFormulas, xlPasteValues
Else
targetWbk.Sheets("sheet1").Cells(A1, Columns.Count).End(xlToLeft).Offset(0, 1).PasteSpecial xlPasteFormulas, xlPasteValues
End If
MyFile = Dir
End If
Loop
End Sub
在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)