Как получить значение из вложенной карты типа AnyRef - PullRequest
0 голосов
/ 29 марта 2019

Итак, у меня есть карта типа

Map[String, AnyRef]

Когда я печатаю эту карту через println, она дает следующий вывод

Map(revision -> 
 Map(comment -> "string1", 
     contributor -> Map(id -> "int1", username -> "string2"), 
     format -> "string3", 
     id -> "int2", 
     minor -> None, 
     model -> "string4", 
     parentid -> "int3", 
     sha1 -> "string5", 
     text -> Map(_VALUE -> "VALUE-THAT-I-WANT-TO-GET", 
     space -> ""), 
     timestamp -> Timestamp, 
     title -> "string6"))

Теперь, как вы видите на карте, я хочу получить значение против ключа _VALUE.

Я пытался получить его так, как вы получаете от вложенной карты, объясненной в этом ответе, но это не сработало, возможно, потому что он имеет тип AnyRef
Каков наилучший способ получить его в простой строковой переменной?

Извините, если карта недостаточно читаема, я приму, если вы отредактируете ее лучше. Но он был опубликован полностью, чтобы прояснить смысл проблемы.

Ответы [ 3 ]

4 голосов
/ 29 марта 2019

Итак, допустим, у вас есть коллега, который создает такой код. Конечно, этот человек уволен за некомпетентность. Увы, вы застряли с задачей поработать с ней, пока она не будет переписана в надлежащий Scala.

Вот одна вещь, которую вы могли бы сделать. Он компилируется с предупреждением, но, похоже, дает желаемый результат.

def extract(m :collection.Map[String,AnyRef], key :String) :Option[String] = {
  if (m.isDefinedAt(key)) Some(m(key).toString)
  else {
    val res = m.values
               .collect{case ma:Map[String,AnyRef] => extract(ma,key)}
               .dropWhile(_.isEmpty)
    if (res.isEmpty) None else res.head
  }
}

extract(badMap, "_VALUE") //res0: Option[String] = Some(VALUE-THAT-I-WANT-TO-GET)
extract(badMap, "_XALUE") //res1: Option[String] = None
3 голосов
/ 29 марта 2019

Вы можете обернуть свою карту (псевдоним anymap), чтобы определить метод getAs [T], который возвращает Option и так далее ...

import scala.reflect.ClassTag

val m: Map[String, AnyRef] = Map("a" -> Map("b" -> Map("c" -> "d")))

type AnyMap = Map[String, AnyRef]

implicit class AnyMapWrapper(m: AnyMap) {
    def getAs[T](key: String)(implicit ev: ClassTag[T]): Option[T] = m(key) match {
        case i: T => Some(i.asInstanceOf[T])
      case _ => None
  }
}

println {
    m.getAs[AnyMap]("a").flatMap(_.getAs[AnyMap]("b")).map(_("c"))
}

println {
  for {
    a <- m.getAs[AnyMap]("a")
    b <- a.getAs[AnyMap]("b")
  } yield b("c")
}
0 голосов
/ 29 марта 2019

Подробная (но явная) версия может быть:

yourMap.get("revision") collect {
  case Some(otherMap: Map[String, AnyRef]) => otherMap.get("text")
} collect {
  case Some(yetAnotherMap: Map[String, AnyRef]) => yetAnotherMap.get("_VALUE")
}
...