1

が与えられたMap[Int, Set[Int]]場合、Map の単一の値を変更して、その過程で新しい値を生成するにはどうすればよいですか。たとえば、次のようになります。

val x = Map(1 -> Set(1,2,3))
x(1) + 5 // This creates a new Set, but not a new Map

val y = x(1) change { x => x + 5 }
// The previous functionality is what I'm looking for
// z: Set[Int]] = List(Set(1, 2, 3, 5))
4

7 に答える 7

5

ロビン・グリーンが示唆するように、レンズはこの仕事のために作られています。実際、マップはキー -> 値の部分関数であるため、部分レンズが必要です。

Scalaz 7 には、選択したキーの値にmapVPLens部分レンズ ( ) を作成する関数が含まれています。PLens

import scalaz.PLens._
val x = Map(1 -> Set(1,2,3))

mapVPLens(1) mod ((_: Set[Int]) + 5, x) // Map(1 -> Set(1, 2, 3, 5))

存在しないキーの値を変更しても効果はありません。

mapVPLens(9) mod ((_: Set[Int]) + 5, x) // Map(1 -> Set(1,2,3))
于 2013-01-21T22:21:40.543 に答える
4

scala 2.10 では:

implicit class ChangeableMap[K,V]( val m: Map[K,V] ) extends AnyVal {
  def change( k: K )( transform: V => V ): Map[K,V] = {
    m.get( k ).map{ v => m + (k-> transform(v)) }.getOrElse( m )
  }
}

いくつかのテスト:

scala>val x = Map(1 -> Set(1,2,3), 2 -> Set(4,5))
x: scala.collection.immutable.Map[Int,scala.collection.immutable.Set[Int]] = Map(1 -> Set(1, 2, 3), 2 -> Set(4, 5))
scala> x.change(1) { x => x + 5 }
res1: Map[Int,scala.collection.immutable.Set[Int]] = Map(1 -> Set(1, 2, 3, 5), 2 -> Set(4, 5))

scala 2.9 を使用している場合は、次のようになります。

class ChangeableMap[K,V]( m: Map[K,V] ) {
  def change( k: K )( transform: V => V ): Map[K,V] = {
    m.get( k ).map{ v => m + (k-> transform(v)) }.getOrElse( m )
  }
}
implicit def toChangeableMap[K,V]( m: Map[K,V] ) = new ChangeableMap[K,V]( m )
于 2013-01-21T22:02:11.943 に答える
3

レンズを使おう!

ただし、レンズを定義する Scalaz 6 には、状況に合わせて事前に作成された特定のレンズがありません。これは、少し手間がかかることを意味します - Map が別のオブジェクトに含まれている場合は、(十分に隠された)その状況のサポート。また、Scalaz 7 にはスタンドアロンの Maps 用のレンズが含まれます。

また、レンズは単なる機能のペアであり、言語サポートを必要としないため、独自のものを展開することができます.

于 2013-01-21T21:19:44.667 に答える
1

を使うのが一番簡単だと思いますscala.collection.mutable.Map

import scala.collection.mutable.Map

val m = Map(1 -> Set(1,2,3))
m.update(1, m(1) + 5)
// now the Map looks like this: Map(1 -> Set(1,2,3,5))

不変のマップを取得した場合は、次を使用して単純に変更可能なマップに変換できます。

val n: collection.mutale.Map(m.toSeq: _*)

不変の Map を返す必要がある場合、これは逆の方法でも機能します。

于 2013-01-22T09:20:45.883 に答える
1

これは私たちのコードベースからの 1 つです。

/**
 * Alters a value in a map.
 *
 * modifyMap :: Map k v -> k -> (Maybe v -> Maybe v) -> Map k v
 * See Haskell's Data.Map.alter
 *
 * @param m   the map to modify
 * @param key the key to modify the value of
 * @param mod a function that takes the existing value (if any) and returns an optional new value
 *
 * @return the modified map
 */
def modifyMap[K,V](m: Map[K,V], key: K)
                  (mod: (Option[V] ⇒ Option[V])): Map[K,V] = {
  mod(m.get(key)) match {
    case Some(newVal) ⇒ m + (key → newVal)
    case None ⇒ m - key
  }
}

そして、これを使用する方法は次のとおりです。

modifyMap(myMap, "someKey") { 
  case Some(someVal) => 
    // present
    if (condition) 
      Some(valueDerivedFrom(someVal)) // provide a new mapping for someKey
    else 
      None // someKey will now be unset
  case None => 
    // wasn't present
    if (condition)
      Some(newValue) // provide a new value for someKey
    else
      None // leave someKey unset
}
于 2013-01-21T21:14:35.500 に答える
1

この問題を解決する非常に慣用的な方法は次のようになります ( Viktor Klangに感謝します):

val x = Map(1 -> Set(1,2,3), 2 -> Set(1), 3 -> Set(5))
x.map { case (1, v) => (1, v + 5); case x => x }
// res0: Map(1 -> Set(1, 2, 3, 5))

または、クラスと暗黙的にうまくパックされます。

class ChangeableMap[K,V](map:Map[K,V]) {
    def change(index:K)(f:V => V) = map.map {
        case (`index`, v:V) => (index, f(v))
        case x => x
    }
}

object ChangeableMap {
    implicit def fromMap[K,V](map:Map[K,V]) = new ChangeableMap(map)
}

前の宣言では、次のように動作します。

x.change(1) { x => x + 5 }
x.change(1) { _ + 5 }
// res1:  Map(1 -> Set(1, 2, 3, 5))

Scala がマップ全体を反復処理する (おそらく確認されていない) ことを考えると、これはおそらく最速のソリューションではないことに注意してください!

おそらくより高速な実装は次のとおりです(ただし、実際に高速かどうかは確認していません)。

class ChangeableMap[K,V](map:Map[K,V]) {
    def change(index:K)(f:V => V) = map.get(index) match {
        case Some(x) => map + ((index, f(x)))
        case None => map
    }
}
于 2013-01-21T21:08:25.450 に答える
0

前述のように、この種の問題には Partial Lens を使用できます。scalazMonocleはそれを実装しています。モノクルでそれを行う方法は次のとおりです。

import monocle.syntax.taversal._ // to use |->>
import monocle.syntax.at._       // to use at

val x = Map(1 -> Set(1,2,3))

x |->> at(1) modify(_ + 5) == Map(1 -> Set(1,2,3,5))  
于 2014-05-12T11:01:40.077 に答える