web-dev-qa-db-ja.com

不変Scala挿入順序を保持するマップ実装

LinkedHashMapはマップの挿入順序を維持するために使用されますが、これは変更可能なマップでのみ機能します。挿入順序を保持する不変のMap実装はどれですか?

51
Matroska

ListMap は、リストベースのデータ構造を使用して不変マップを実装するため、挿入順序が保持されます。

scala> import collection.immutable.ListMap
import collection.immutable.ListMap

scala> ListMap(1 -> 2) + (3 -> 4)
res31: scala.collection.immutable.ListMap[Int,Int] = Map(1 -> 2, 3 -> 4)

scala> res31 + (6 -> 9)
res32: scala.collection.immutable.ListMap[Int,Int] = Map(1 -> 2, 3 -> 4, 6 -> 9)

次の拡張メソッド-Seq#toListMapは、ListMapsを使用する場合に非常に役立ちます。

scala> import scalaz._, Scalaz._, Liskov._
import scalaz._
import Scalaz._
import Liskov._

scala> :paste
// Entering paste mode (ctrl-D to finish)

implicit def seqW[A](xs: Seq[A]) = new SeqW(xs)
class SeqW[A](xs: Seq[A]) {
  def toListMap[B, C](implicit ev: A <~< (B, C)): ListMap[B, C] = {
    ListMap(co[Seq, A, (B, C)](ev)(xs) : _*)  
  }
}


// Exiting paste mode, now interpreting.

seqW: [A](xs: Seq[A])SeqW[A]
defined class SeqW

scala> Seq((2, 4), (11, 89)).toListMap
res33: scala.collection.immutable.ListMap[Int,Int] = Map(2 -> 4, 11 -> 89)
52
missingfaktor

ListMapは挿入順序を保持しますが、あまり効率的ではありません。ルックアップ時間は線形です。 _immutable.HashMap_と_immutable.TreeMap_の両方をラップする新しいコレクションクラスを作成することをお勧めします。不変マップはimmutable.HashMap[Key, (Value, Long)]としてパラメーター化する必要があります。タプルのLongは、_TreeMap[Long, Key]_の対応するエントリへのポインターを提供します。その後、側面にエントリーカウンターを置きます。このツリーマップは、挿入順序に従ってエントリを並べ替えます。

挿入とルックアップは単純な方法で実装します。カウンターをインクリメントし、ハッシュマップに挿入し、カウンターキーのペアにツリーマップに挿入します。ルックアップにはハッシュマップを使用します。

ツリーマップを使用して反復を実装します。

削除を実装するには、ハッシュマップからキーと値のペアを削除し、タプルのインデックスを使用して、対応するエントリをツリーマップから削除する必要があります。

22
axel22