2010-12-01 1 views
9

Я структура три уровня данных (отступы и разрывы строк для удобства чтения):Как получить доступ и обновлять значение в изменяемой карте карты карты

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, поэтому все другие замечания по приведенному выше коду также приветствуются.

ответ

21

Вы не должны использовать "применять" только делают это обычно с "()"

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

Это работает в этом примере, но не будет работать, если m («normal») («home») еще не определен. – Mark 2016-10-12 00:46:48

10

Вы можете написать

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

в

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

Однако я Не уверен, что такая структура является хорошей идеей. Возможно, вам стоит рассмотреть возможность инкапсуляции этой функции в специализированный класс.

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) 
    } 
} 

[Edit сделал код туже]

+0

Умный! (Я просто надеюсь, что не слишком умный :) Принял несколько показаний, прежде чем я понял, что здесь происходит. Отличный ответ, спасибо! – user272735 2010-12-01 20:01:52

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) 

который использует синтаксический сахар для получения и установок (газопоглощающего определение сусла существует для определения сеттера работать).

+0

Это тоже очень полезный ответ - спасибо! Я желаю вам много внимания. Геттер/сеттер объясняется для начинающих: http://www.dustinmartin.net/2009/10/getters-and-setters-in-scala/ – user272735 2010-12-02 07:15:12

Смежные вопросы