当我通过标准调用Map()
或通过连接以这种方式创建的现有地图来创建不可变地图时,在我的所有测试中,我发现遍历其成员会按添加顺序提供它们。这正是我需要对它们进行排序的方式,但文档中没有关于地图成员排序的可靠性的文字。
所以我想知道期望标准 Map 按添加顺序返回其项目是否安全,或者我应该寻找其他一些实现以及在这种情况下哪些实现。
我认为这不安全,从 5 个元素(Scala 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
实现排序条目。
挖掘后,我发现存在一个不可变的行为,它的ListMap
行为完全符合我的要求,但根据这张表,它的性能非常糟糕。所以我编写了一个自定义的不可变实现,它应该在除删除之外的所有操作上有效执行,它线性执行。它确实需要更多的内存,因为它由标准Map
和 a支持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)
}
}
没有关于订单的承诺Map
。有一个OrderedMap
in scalas 集合包。该包中的值按隐式排序Ordering
。作为快速修复,我建议您使用键列表来排序您的地图。
var keyOrdering = List[Int]()
var unorderedMap = Map[Int, String]()
unorderedMap += (1 -> "one")
keyOrdering :+= 1
编辑
您可以实现自己的Ordering
并将其传递给 a 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)
隐式 Ordering 应用于键,因此IntOrdering
可能应用于SortedMap[Int, Any]
.
编辑#3
像我的评论中这样的自排序 DataType 可能看起来像这样:
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
}
我希望这是您期望我回答的方式。