【问题标题】:How to implement Map with default operation in Scala如何在 Scala 中使用默认操作实现 Map
【发布时间】:2011-08-15 09:15:44
【问题描述】:
class DefaultListMap[A, B <: List[B]] extends HashMap[A, B] {
    override def default(key: A) = List[B]() 
  }

我不想创建地图A -&gt; List[B]。就我而言,它是Long -&gt; List[String],但是当我从没有价值的地图中获取密钥时,我想创建空的List,而不是抛出Exception。我尝试了不同的组合,但我不知道如何让上面的代码通过编译器。

提前致谢。

【问题讨论】:

  • 我使用code val map = new HashMap[Long, List[String]]() { override def default(key: Long) = List[String]() } 解决了我的问题

标签: scala scala-collections


【解决方案1】:

为什么不使用 withDefaultValue(value)?

scala> val m = Map[Int, List[String]]().withDefaultValue(List())
m: scala.collection.immutable.Map[Int,List[String]] = Map()

scala> m(123)
res1: List[String] = List()

【讨论】:

【解决方案2】:

您总是可以使用get,而不是使用apply 来访问地图,它会返回Option[V],然后是getOrElse

map.get(k) getOrElse Nil

scalaz 函数式编程库的一大特色是一元运算符~,意思是“或零”,只要值类型有一个定义了“零”(List 确实如此,零当然是Nil)。于是代码就变成了:

~map.get(k)

这是双重有用的,因为相同的语法适用于(例如)您的值是 IntDouble 等(任何有 Zero 类型类的东西)。


关于使用 Map.withDefault 的 scala 邮件列表上有很多争论,因为它在 isDefinedAt 方法等方面的表现如何。出于这个原因,我倾向于避开它。

【讨论】:

  • 有趣的答案。但是,从地图创建到地图访问的未定义项目的管理是在哪里完成的。在我的情况下,我需要将 Map 传递给一个已经有自己的默认行为的方法,我想覆盖它(用于测试)。而且我无法更改读取地图的代码。
  • 这是一个很好的答案,因为如果它不在地图中,它会在调用代码中清楚地表明值的来源。减少魔法。
  • 现在可以写成:map.getOrElse(k, Nil)
【解决方案3】:

withDefaultValue 上有一个方法 withDefaultValue

scala> val myMap = Map(1 -> List(10), 2 -> List(20, 200)).withDefaultValue(Nil)
myMap: scala.collection.immutable.Map[Int,List[Int]] = Map((1,List(10)), (2,List(20, 200)))

scala> myMap(2)
res0: List[Int] = List(20, 200)

scala> myMap(3)
res1: List[Int] = List()

【讨论】:

【解决方案4】:

既然已经有方法,为什么还要操作地图?

val m = Map(1L->List("a","b"), 3L->List("x","y","z"))  
println(m.getOrElse(1L, List("c"))) //--> List(a, b)
println(m.getOrElse(2L, List("y"))) //--> List(y)

【讨论】:

  • 查看我对@oxbow_lakes 的评论:这与 OP 的要求不同。它在地图访问时而不是在地图创建时管理默认值。
【解决方案5】:

withDefault 也可以使用。

/** The same map with a given default function.
 *  Note: `get`, `contains`, `iterator`, `keys`, etc are not affected
 *  by `withDefault`.
 *
 *  Invoking transformer methods (e.g. `map`) will not preserve the default value.
 *
 *  @param d     the function mapping keys to values, used for non-present keys
 *  @return      a wrapper of the map with a default value
 */
 def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1]

例子:

scala> def intToString(i: Int) = s"Integer $i"
intToString: (i: Int)String

scala> val x = Map[Int, String]().withDefault(intToString)
x: scala.collection.immutable.Map[Int,String] = Map()

scala> x(1)
res5: String = Integer 1

scala> x(2)
res6: String = Integer 2

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    相关资源
    最近更新 更多