【问题标题】:How to concatenate two MapViews to get a MapView?如何连接两个 MapView 以获得 MapView?
【发布时间】:2021-11-14 00:42:11
【问题描述】:

以下代码无法使用 Scala 2.13.6 编译:

val a = Map(0 -> "0")
val b = Map(1 -> "1")

val c = a.view ++ b.view

c.contains(0)

错误是:

值包含不是 scala.collection.View[(Int, String)] 的成员

Scala 3 或 Scala 2.12.15 中显示了类似的错误。

我发现这出乎意料,因为concat 的实现似乎表明结果应该是一个地图(mapFactory 用于生成结果)。

如何连接两个MapViews 以再次获得MapView

【问题讨论】:

  • 尝试添加toMap。看看MapView(<not computed>) in Scala
  • 好吧,我的结果不是 MapView(未计算),而是 View(未计算)。首先使用 toMap 会破坏使用视图的目的。我可以使用一个简单的a ++ b。我想避免中间集合,因为 a 和 b 非常大。
  • ++ 返回一个View[(Int, String)],它不是map,你不能对它执行contains。你可以做.toMap,或者在每个视图上做包含,或者在结果View上做collectFirst。我没有看到任何其他选项。
  • 类似:val result = Seq(a, b).exists(_.view.contains(0))
  • 查看github.com/scala/scala/pull/8082了解一些背景信息。

标签: scala collections


【解决方案1】:

基于Remove concat, ++ and + overloads from MapView,它被设计删除了,但也许您仍然可以提供自己的扩展方法来模仿以前的实现,就像这样

implicit class ConcatMapView[K, +V](left: MapView[K, V]) {
  def +++[V1 >: V](right: MapView[K, V1]): MapView[K, V1] =
    new AbstractMapView[K, V1] {
      def get(key: K): Option[V1] = right.get(key) match {
        case s @ Some(_) => s
        case _           => left.get(key)
      }
      def iterator: Iterator[(K, V1)] = left.iterator
        .filter { case (k, _) => !right.contains(k) }
        .concat(right.iterator)
    }
}

val c = a.view +++ b.view // : MapView[Int, String] = MapView((0, "0"), (1, "1"))
c.contains(0) // : Boolean = true

【讨论】:

    【解决方案2】:

    我不知道 concat 不返回 MapView 背后的意图,但您可以像这样实现您的目标:

    val a = Map(0 -> "0")
    val b = Map(1 -> "1")
    
    val c = a.view ++ b.view
    
    val contains = c.exists((k,v) => k == 0)
    

    【讨论】:

    • "c.exists" 是 O(N),这对于大型集合来说是个问题 - 而对于小型集合来说,根本没有令人信服的理由使用视图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 2017-12-23
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    相关资源
    最近更新 更多