【问题标题】:How to transform a collection of tuples with scala 2.13如何使用 scala 2.13 转换元组集合
【发布时间】:2021-06-09 22:47:55
【问题描述】:

我想将以下代码从 Scala 2.12 迁移到 2.13

给定任何元组集合Coll[(A, B)] 和方法f: B => IterableOnce[C],我想通过在元组的第二个元素上应用f 来生成Coll[(A, C)]

implicit class TuplesOps[A, B, Repr <: Traversable[(A, B)]](val s: TraversableLike[(A, B), Repr]) extends AnyVal {
  def flatMapValues[C, That](f: B => TraversableOnce[C])(implicit bf: CanBuildFrom[Repr, (A, C), That]) =
    s.flatMap { case (a, b) => f(b).map((a, _))}
}

我知道集合 API 在 2.13 中发生了变化,我读到:https://docs.scala-lang.org/overviews/core/custom-collection-operations.html

我已经尝试了 2 种实现方式

第一

import scala.collection.{ AbstractView, BuildFrom }
import scala.collection.generic.IsSeq

object Evidence extends App {
  class TuplesOps[Repr, S <: IsSeq[Repr]](coll: Repr, seq: S) {
    def flatMapValues[B, C, D, That](f: C => IterableOnce[D])(implicit bf: BuildFrom[Repr, (B, D), That], ev: seq.A =:= (B, C)): That = {
      val seqOps = seq(coll)
      bf.fromSpecific(coll)(new AbstractView[(B, D)] {
        override def iterator: Iterator[(B, D)] = {
          seqOps.flatMap { x => f(ev(x)._2).map((ev(x)._1, _))}.iterator
        }
      })
    }
  }

  implicit def TuplesOps[Repr](coll: Repr)(implicit seq: IsSeq[Repr]): TuplesOps[Repr, seq.type] =
    new TuplesOps(coll, seq)

  List("a"->1, "b"->2).flatMapValues{(x:Int) => Seq.fill(x)("x")}
}

我有这个编译错误:

[error] /home/yamo/projects/perso/coll213/src/main/scala/example/Evidence.scala:22:37: diverging implicit expansion for type scala.collection.BuildFrom[List[(String, Int)],(B, String),That]
[error] starting with method Tuple9 in object Ordering
[error]   List("a"->1, "b"->2).flatMapValues{(x:Int) => Seq.fill(x)("x")}

第二

import scala.collection.{ AbstractView, BuildFrom }
import scala.collection.generic.IsSeq

object Aux extends App {
  type Aux[Repr, B, C] = IsSeq[Repr] { type A = (B, C)}

  class TuplesOps[Repr, B, C, S <: Aux[Repr, B, C]](coll: Repr, seq: S) {
    def flatMapValues[D, That](f: C => IterableOnce[D])(implicit bf: BuildFrom[Repr, (B, D), That]): That = {
      val seqOps = seq(coll)
      bf.fromSpecific(coll)(new AbstractView[(B, D)] {
        // same as before
        override def iterator: Iterator[(B, D)] = {
          seqOps.flatMap { case (b, c) => f(c).map((b, _))}.iterator
        }
      })
    }
  }

  implicit def TuplesOps[Repr, B, C](coll: Repr)(implicit seq: Aux[Repr, B, C]): TuplesOps[Repr, B, C, seq.type] =
    new TuplesOps(coll, seq)

  List("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))
}

我有这个编译错误

[error] /home/yamo/projects/perso/coll213/src/main/scala/example/Aux.scala:24:24: value flatMapValues is not a member of List[(String, Int)]
[error]   List("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))

如果可能的话,你能帮我让这两个解决方案都起作用吗?

【问题讨论】:

  • 你能用文字定义一下你原来的功能是做什么的吗?
  • 给定一个元组集合,代码对元组的第二个元素应用一个函数(元组集合上的一种 flatMap)。
  • 该方法应该适用于任何集合,而不仅仅是List

标签: scala collections scala-2.13


【解决方案1】:

我同意,Custom Collection instructions 不是应有的样子。

我发现Factory 方法比BuildFrom 更容易一些,但我仍然习惯了其中一个/两个。

import scala.collection.Factory

implicit
class TuplesOps[A,B,CC[x] <: Iterable[x]](val ts: CC[(A,B)]) {
  def flatMapValues[C](f: B => IterableOnce[C]
                      )(implicit fac: Factory[(A,C), CC[(A,C)]]
                       ): CC[(A,C)] =
    ts.flatMap{case (a,b) => f(b).iterator.map(x => (a,x))}
      .to[CC[(A,C)]](fac)
}

这通过了我所有的简单(头脑)测试。它不适用于ArrayIterator,但是您原来的 Scala 2.12.x 版本也不起作用(对我而言),所以我认为没关系。

【讨论】:

  • 谢谢。你知道如何让我的解决方案发挥作用吗?
  • 我还没有使IsSeq 解决方案工作。如果/当我这样做时,我会告诉你的。
猜你喜欢
  • 2021-06-21
  • 2019-03-18
  • 2021-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-15
  • 2019-08-08
  • 1970-01-01
相关资源
最近更新 更多