當我創建一個不可變的地圖時,通過對Map()
的標準調用或通過連接現有地圖創建這種方式,在所有我的測試中,我得到遍歷它的成員按添加的順序提供它們。這正是我需要對它們進行排序的方式,但文檔中沒有關於地圖成員排序可靠性的文字。地圖成員的排序是否似乎是可靠的?
所以我想知道是否可以安全地期望標準Map按照添加的順序返回它的項目,或者我應該尋找其他的實現以及在這種情況下的哪些實現。
當我創建一個不可變的地圖時,通過對Map()
的標準調用或通過連接現有地圖創建這種方式,在所有我的測試中,我得到遍歷它的成員按添加的順序提供它們。這正是我需要對它們進行排序的方式,但文檔中沒有關於地圖成員排序可靠性的文字。地圖成員的排序是否似乎是可靠的?
所以我想知道是否可以安全地期望標準Map按照添加的順序返回它的項目,或者我應該尋找其他的實現以及在這種情況下的哪些實現。
我不認爲它是安全的,不保留的順序從5個元素(斯卡拉2.9.1)開始:
scala> Map(1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4, 5 -> 5)
res9: scala.collection.immutable.Map[Int,Int] =
Map(5 -> 5, 1 -> 1, 2 -> 2, 3 -> 3, 4 -> 4)
有了更大的映射的順序是完全「隨機」,嘗試Map((1 to 100) zip (1 to 100): _*)
。
嘗試LinkedHashMap
訂購條目和TreeMap
以實現排序條目。
Yikes!這在2.10.0-M3中是可重現的。好的,對於問題的第二部分:對於我的情況,您會推薦哪種實現? –
@NikitaVolkov:嘗試['LinkedHashMap'](http://www.scala-lang.org/api/current/scala/collection/mutable/LinkedHashMap.html)訂購條目和['TreeMap'](http:/ /www.scala-lang.org/api/current/scala/collection/immutable/TreeMap.html)來實現排序條目。 –
謝謝,但雖然'LinkedHashMap'的確可以正確地排列項目,但它是可變的。我知道不可變的'ListMap',它也可以做到這一點,但根據[this](http://www.scala-lang.org/docu/files/collections-api/collections_40.html),它的表現非常好。所以看起來我必須處理它或進行自定義實現 - 對嗎? –
對於Map
的訂單沒有承諾。在scalas收集包中有一個OrderedMap
。該包中的值由隱含的Ordering
排序。作爲quickfix,我建議你使用一個鍵列表來排列你的Map。
var keyOrdering = List[Int]()
var unorderedMap = Map[Int, String]()
unorderedMap += (1 -> "one")
keyOrdering :+= 1
編輯
你可以實現自己的Ordering
,並把它傳遞給一個SortedMap
爲好。
編輯#2
一個簡單的例子是下面的:
scala> import scala.collection.SortedMap
import scala.collection.SortedMap
scala> implicit object IntOrdering extends Ordering[Int]
| def compare(a: Int, b: Int) = b - a
| }
defined module IntOrdering
scala> var sm = SortedMap[Int, String]()
sm: scala.collection.SortedMap[Int,String] = Map()
scala> sm += (1 -> "one")
scala> sm += (2 -> "two")
scala> println(sm)
Map(2 -> two, 1 -> one)
隱式排序被應用到密鑰,所以IntOrdering
可能被施加到SortedMap[Int, Any]
。
編輯#3
自訂貨數據類型一樣在我的評論看起來是這樣的:
case class DataType[T](t: T, index: Int)
object DataType{
private var index = -1
def apply[T](t: T) = { index += 1 ; new DataType[T](t, index)
}
現在,我們需要改變排序:
implicit object DataTypeOrdering extends Ordering[DataType[_]] {
def compare(a: DataType[_], b: DataType[_]) = a.index - b.index
}
希望這是你期待我的答案的方式。
你可否詳細說一下'Ordering'和'SortedMap'多一點? –
我用一個簡單的例子更新了我的答案。 –
謝謝,但它是不正確的:你通過鍵排序的地圖,而不是通過添加順序在這兩個示例 –
挖掘之後,我發現存在一個不可變的ListMap
,其行爲與我想要的完全一樣,但根據this table,其性能只是很差。所以我寫了一個自定義的不可變實現,它應該對除了刪除之外的所有操作都有效地執行,並在其中線性執行。它確實需要更多的內存,因爲它有一個標準的Map
和Queue
作爲後盾,後者本身使用了List
兩次,但在當前時代這不是問題,對。
import collection.immutable.Queue
object OrderedMap {
def apply[A, B](elems: (A, B)*) =
new OrderedMap(Map(elems: _*), Queue(elems: _*))
}
class OrderedMap[A, B](
map: Map[A, B] = Map[A, B](),
protected val queue: Queue[(A, B)] = Queue()
) extends Map[A, B] {
def get(key: A) =
map.get(key)
def iterator =
queue.iterator
def +[B1 >: B](kv: (A, B1)) =
new OrderedMap(
map + kv,
queue enqueue kv
)
def -(key: A) =
new OrderedMap(
map - key,
queue filter (_._1 != key)
)
override def hashCode() =
queue.hashCode
override def equals(that: Any) =
that match {
case that: OrderedMap[A, B] =>
queue.equals(that.queue)
case _ =>
super.equals(that)
}
}
通常不建議依靠實施細節。也就是說,'scala.collection.immutable.Map [A,B]'實現'Iterable [(A,B)]'而不是'Seq [(A,B)]',這將保證順序。 – ziggystar
而不是使用'Map [K,V]'你可以使用'Map [K,(V,Int)]'其中'Int'它的插入索引。然後調用'toSeq'並在該字段上排序,如果需要將所有對提取爲一個序列。 –