Скала - уменьшить / сложить - PullRequest
4 голосов
/ 11 октября 2011

У меня есть вложенная карта m, которая выглядит следующим образом:

m = Map("email" -> "a@b.com", "background" -> Map("language" -> "english"))

У меня есть массив arr = Array("background","language")

Как мне сложить / уменьшитьмассив и найти строку "английский" с карты.Я попробовал это:

arr.foldLeft(m) { (acc,x) => acc.get(x) }

Но я получаю эту ошибку:

<console>:10: error: type mismatch;
 found   : Option[java.lang.Object]
 required: scala.collection.immutable.Map[java.lang.String,java.lang.Object]
       arr.foldLeft(m) { (acc,x) => acc.get(x) }

Ответы [ 2 ]

12 голосов
/ 11 октября 2011

Стоит обратить внимание на типы.Здесь вы начинаете с m : Map[String, Any] в качестве вашего соотв.Вы комбинируете со строкой x и вызываете get, которая возвращает Option[Object].Чтобы продолжить, вы должны проверить, есть ли значение, проверить, является ли это значение Map, приведение (не проверено из-за стирания типа, следовательно, опасно).

Я считаю, что ошибка в том, что тип вашей структуры, Map [String, Any], представляет то, что у вас довольно плохо.

Предположим, вы делаете вместо этого

sealed trait Tree
case class Node(items: Map[String, Tree]) extends Tree
case class Leaf(s: String) extends Tree

Вы можете добавить несколько помощников, чтобы упростить объявление дерева

object Tree {
  implicit def fromString(s: String) = Leaf(s)
  implicit def fromNamedString(nameAndValue: (String, String)) 
    = (nameAndValue._1, Leaf(nameAndValue._2))
}
object Node {
  def apply(items: (String, Tree)*) : Node = Node(Map(items: _*))
}

Тогда объявление дерева так же просто, как и ваше первоеверсия, но тип гораздо более точный

m = Node("email" -> "a@b.com", "background" -> Node("language" -> "english"))

Затем можно добавить методы, например, в trait Tree

  def get(path: String*) : Option[Tree] = {
    if (path.isEmpty) Some(this)
    else this match {
      case Leaf(_) => None
      case Node(map) => map.get(path.head).flatMap(_.get(path.tail: _*))
    }
  }
  def getLeaf(path: String*): Option[String] 
    = get(path: _*).collect{case Leaf(s) =>s}

Или, если вы предпочитаете делать это со сгибом

  def get(path: String*) = path.foldLeft[Option[Tree]](Some(this)) {
    case (Some(Node(map)), p) => map.get(p)
    case _ => None
  }
4 голосов
/ 11 октября 2011

Складывание как абстракция над вложенными картами не поддерживается. Кроме того, вы подходите к этому таким образом, чтобы помешать системе типов оказать вам большую помощь. Но если вы настаиваете, то вам нужна рекурсивная функция:

def lookup(m: Map[String,Object], a: Array[String]): Option[String] = {
  if (a.length == 0) None
  else m.get(a(0)).flatMap(_ match {
    case mm: Map[_,_] => lookup(mm.asInstanceOf[Map[String,Object]],a.tail)
    case s: String if (a.length==1) => Some(s)
    case _ => None
  })
}
...