9

私は3つのレベルのデータ構造を持っています(読みやすくするためのインデントと改行):

scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map

scala> val m = Map("normal" -> Map("home" -> Map("wins" -> 0, "scores" -> 0),
                                   "away" -> Map("wins" -> 0, "scores" -> 0)))
m: scala.collection.mutable.Map[java.lang.String,
   scala.collection.mutable.Map[java.lang.String,
   scala.collection.mutable.Map[java.lang.String,Int]]] = 
Map((normal,Map(away -> Map(wins -> 0, scores -> 0),
     home -> Map(wins -> 0, scores -> 0))))

最も内側のデータ(スコア)にアクセスするには、多くの入力が必要です。

import org.scalatest.{Assertions, FunSuite}

class MapExamplesSO extends FunSuite with Assertions {
  test("Update values in a mutable map of map of maps") {
    import scala.collection.mutable.Map
    // The m map is essentially an accumulator
    val m = Map("normal" -> 
                Map("home" -> Map("wins" -> 0, "scores" -> 0),
                    "away" -> Map("wins" -> 0, "scores" -> 0)
                  )
          )
    //
    // Is there a less verbose way to increment the scores ?
    //
    assert(m("normal").apply("home").apply("scores") === 0)

    val s1 = m("normal").apply("home").apply("scores") + 1
    m("normal").apply("home").update("scores", s1)

    assert(m("normal").apply("home").apply("scores") === 1)

    val s2 = m("normal").apply("home").apply("scores") + 2
    m("normal").apply("home").update("scores", s2)

    assert(m("normal").apply("home").apply("scores") === 3)
  }
}

スコアの値を変更するためのより冗長な方法はありますか?

私はScalaの初心者なので、上記のコードの他のすべての観察も歓迎します。

4

4 に答える 4

21

「apply」を使用する必要はありません。通常は「()」を使用してください。

m("normal")("home")("scores") = 1
于 2010-12-01T12:59:23.643 に答える
10

あなたは書ける

m("normal").apply("home").apply("scores")

なので

m("normal")("home")("scores")

しかし、そのような構造が良い考えかどうかはわかりません。たぶん、この機能を特殊なクラスにカプセル化することを検討する必要があります。

于 2010-12-01T13:00:06.650 に答える
3

ローカルヘルパー関数を追加することは、コードの重複を減らすための良い方法です。

class MapExamplesSO {
  def test {
    import scala.collection.mutable.Map
    // The m map is essentially an accumulator
    var m = Map("normal" -> 
                Map("home" -> Map("wins" -> 0, "scores" -> 0),
                    "away" -> Map("wins" -> 0, "scores" -> 0)))


    //Local Helper returns (Old, New)
    def updateScore(k1 : String,k2 : String,k3 : String)
                   (f : Int => Int) : (Int, Int) = {
      val old = m(k1)(k2)(k3)
      m(k1)(k2)(k3) = f(old)
      (old, m(k1)(k2)(k3))
    }

    assert(m("normal")(home")("scores") === 0)
    assert(updateScore("normal","home","scores")(_+1)._2 === 1)
    assert(updateScore("normal","home","scores")(_+2)._2 === 3)
  }
}

[編集によりコードが厳密になりました]

于 2010-12-01T16:01:42.283 に答える
3

冗長性が少ない:

assert(m("normal")("home")("scores") === 0)

val s1 = m("normal")("home")("scores") + 1
m("normal")("home")("scores") = s1

assert(m("normal")("home")("scores") === 1)

val s2 = m("normal")("home")("scores") + 2
m("normal")("home")("scores") = s2

assert(m("normal")("home")("scores") === 3)

applyこれは、上記のように、との両方にupdate構文糖衣があるという事実を利用しています。さらに短い:

// On REPL, put both these definitions inside an object instead
// of entering them on different lines
def scores = m("normal")("home")("scores")
def scores_=(n: Int) = m("normal")("home")("scores") = n

assert(scores === 0)

val s1 = scores + 1
scores = s1

assert(scores === 1)

val s2 = scores + 2
scores = s2

// Just so you see these updates are being made to the map:
assert(m("normal")("home")("scores") === 3)

これは、ゲッターとセッターの構文糖衣を利用します(セッター定義が機能するには、ゲッター定義が存在する必要があります)。

于 2010-12-01T19:51:40.143 に答える