追加 - scala mutable map




コレクションをMap-by-keyに変換する最適な方法は? (8)

@James Iryのソリューションに加えて、折り畳みを使ってこれを実現することも可能です。 私は、このソリューションはタプルメソッドよりもわずかに高速だと思っています(少ないガベージオブジェクトが作成されます)。

val list = List("this", "maps", "string", "to", "length")
val map = list.foldLeft(Map[String, Int]()) { (m, s) => m(s) = s.length }

私がT型のコレクションcを持っていて、(型PTプロパティpがある場合、 map-by-extraction-keyを実行する最良の方法は何ですか?

val c: Collection[T]
val m: Map[P, T]

1つの方法は次のとおりです。

m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }

しかし、今私は変更可能な地図が必要です。 これを行うためのより良い方法が1行にあり、私は不変のマップで終わるのですか? (明らかに、私はJavaのように、上記のものを単純なライブラリユーティリティに変えることができましたが、Scalaではこれは必要ないと思われます)


あなたが達成しようとしていることは、少し不明です。
c 2つ以上のアイテムが同じp共有する場合はどうなりますか? どのアイテムがマップ内のそのpにマップされますか?

これをより正確に見る方法は、 pとそれを持つすべてのc項目の間のマップを生成することです:

val m: Map[P, Collection[T]]

これはgroupByで簡単に実現できます:

val m: Map[P, Collection[T]] = c.groupBy(t => t.p)

それでも元のマップが必要な場合は、たとえば、 pを最初のマップにマップすることができます。

val m: Map[P, T] = c.groupBy(t => t.p) map { case (p, ts) =>  p -> ts.head }

おそらく、リストをマップにする最も効率的な方法ではありませんが、呼び出しコードを読みやすくします。 暗黙のコンバージョンを使用して、 mapByメソッドをListに追加しました。

implicit def list2ListWithMapBy[T](list: List[T]): ListWithMapBy[T] = {
  new ListWithMapBy(list)
}

class ListWithMapBy[V](list: List[V]){
  def mapBy[K](keyFunc: V => K) = {
    list.map(a => keyFunc(a) -> a).toMap
  }
}

コーディングコードの例:

val list = List("A", "AA", "AAA")
list.mapBy(_.length)                  //Map(1 -> A, 2 -> AA, 3 -> AAA)

暗黙的な変換のため、呼び出し側コードはスカラのimplicitConversionsをインポートする必要があることに注意してください。


これは、コレクションを次のようにフォールディングすることによって、不変的に、および単一のトラバーサルで実装できます。

val map = c.foldLeft(Map[P, T]()) { (m, t) => m + (t.getP -> t) }

このソリューションは、不変のマップに追加すると、追加のエントリを持つ新しい不変のマップが返され、この値がフォールド操作によるアキュムレータとして機能するため、機能します。

ここでのトレードオフは、コードとその効率の単純さです。 したがって、大規模なコレクションの場合、 maptoMap適用など、2つのトラバーサル実装を使用するよりも、このアプローチが適している場合があります。


それが価値があるのは、ここでは2つの意味がありません。

scala> case class Foo(bar: Int)
defined class Foo

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

scala> val c = Vector(Foo(9), Foo(11))
c: scala.collection.immutable.Vector[Foo] = Vector(Foo(9), Foo(11))

scala> c.map(((_: Foo).bar) &&& identity).toMap
res30: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))

scala> c.map(((_: Foo).bar) >>= (Pair.apply[Int, Foo] _).curried).toMap
res31: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))

コレクションの後にtoMapを続けてmap()を使用する

val map = list.map(e => (e, e.length)).toMap

可変数のタプルでMapを構築することができます。 したがって、コレクションのmapメソッドを使ってそれをタプルのコレクションに変換し、_ _トリックを使用して結果を可変の引数に変換します。

scala> val list = List("this", "maps", "string", "to", "length") map {s => (s, s.length)}
list: List[(java.lang.String, Int)] = List((this,4), (maps,4), (string,6), (to,2), (length,6))

scala> val list = List("this", "is", "a", "bunch", "of", "strings")
list: List[java.lang.String] = List(this, is, a, bunch, of, strings)

scala> val string2Length = Map(list map {s => (s, s.length)} : _*)
string2Length: scala.collection.immutable.Map[java.lang.String,Int] = Map(strings -> 7, of -> 2, bunch -> 5, a -> 1, is -> 2, this -> 4)

c map (_.getP) zip c

うまく動作し、非常に直感的です







scala-collections