Scala - 减少/向左折叠

发布于 12-08 22:47 字数 644 浏览 2 评论 0原文

我有一个嵌套地图 m ,如下所示:

m = Map("email" -> "[电子邮件受保护]", "背景" -> 地图("语言" -> "english"))

我有一个数组 arr = Array("background","language")

如何向左折叠/减少数组并从地图中找到字符串“english” 。我尝试了这个:

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

I have a nested map m which is like:

m = Map("email" -> "[email protected]", "background" -> Map("language" -> "english"))

I have an array arr = Array("background","language")

How do I foldLeft/reduce the array and find the string "english" from the map. I tried this:

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

But I get this error:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南烟2024-12-15 22:47:56

您应该注意类型。在这里,您从 m : Map[String, Any] 作为您的 acc 开始。您与字符串 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" -> "[email protected]", "background" -> Node("language" -> "english"))

然后你可以添加方法,例如在trait Tree<中/code>

  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
  }

You should pay attention to types. Here, you start with m : Map[String, Any] as your acc. You combine with a string x and calls get, which returns an Option[Object]. To continue, you must check that there is a value, check whether this value is a Map, cast (unchecked because of type erasure, hence dangerous).

I believe the fault is in the that the type of your structure, Map[String, Any] represents what you have rather poorly.

Suppose you do instead

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

You may add some helpers to make declaring a Tree easy

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: _*))
}

Then declaring the tree is just as easy as your first version, but the type is much more precise

m = Node("email" -> "[email protected]", "background" -> Node("language" -> "english"))

You can then add methods, for instance in 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}

Or if you would rather do it with a fold

  def get(path: String*) = path.foldLeft[Option[Tree]](Some(this)) {
    case (Some(Node(map)), p) => map.get(p)
    case _ => None
  }
十级心震2024-12-15 22:47:56

折叠作为嵌套映射的抽象并不受真正支持。另外,您处理此问题的方式将阻止类型系统为您提供太多帮助。但是,如果你坚持,那么你需要一个递归函数:

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

Folding as an abstraction over nested maps isn't really supported. Also, you're approaching this in a way that is going to prevent the type system from giving you much help. But, if you insist, then you want a recursive function:

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
  })
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文