元组序列上的 flatMap
flatMap on a sequence of tuples
给定以下代码:
def flatMap2[A, B, C](s:Seq[(A, B)])(f: B => Seq[C]) : Seq[(A, C)] =
s.flatMap { case (a, b) => f(b).map((a, _)) }
是否有更好的编码方式(也许在 scalaz 中退出)?
你能帮我找个更好的名字吗?
是否有更通用的抽象要使用 (Iterable
, TraversableOnce
)?
问题可能不清楚,此时我会说:
// s1: Seq[(A, B)], f: B => C
val s2: Seq[(A, C)] = s1.map((a, b) => a -> f(b))
这个怎么样:
import scala.collection.GenTraversable
import scala.collection.GenTraversableLike
import scala.collection.GenTraversableOnce
import scala.collection.generic.CanBuildFrom
implicit class WithMapFlatMapValues[A, B, Repr <: GenTraversable[(A, B)]](val self: GenTraversableLike[(A, B), Repr]) extends AnyVal {
def flatMapValues[C, That](f: B => GenTraversableOnce[C])(implicit bf: CanBuildFrom[Repr, (A, C), That]) = {
self.flatMap { case (a, b) => f(b).toIterator.map(a -> _) }
}
}
所以你可以这样做:
Vector("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))
// res1: Vector[(String, String)] = Vector((a,x), (b,x), (b,x))
Set("a"->1, "b"->2).flatMapValues(Iterator.tabulate(_)(_+"x"))
// res2: Set[(String, String)] = Set((a,0x), (b,0x), (b,1x))
你也可以用 Iterator 来做(这样你就涵盖了所有的 TraversableOnce):
implicit class WithMapFlatMapValuesItr[A, B](val self: Iterator[(A, B)]) extends AnyVal {
def flatMapValues[C](f: B => GenTraversableOnce[C]) = {
for { (a, b) <- self; c <- f(b).toIterator } yield (a -> c)
}
}
val i1 = Iterator("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))
// i1: Iterator[(String, String)] = non-empty iterator
i1.toVector
// res6: Vector[(String, String)] = Vector((a,x), (b,x), (b,x))
看起来好一点:
def flatMap2[A, B, C](List[(A, B)])(f: B => Seq[C]) : List[(A, C)] =
for((a,b) <- s; bb <- f(b)) yield a -> bb
但是您在这里尝试做的事情更像是关于多映射(保留顺序),而不仅仅是元组序列:
def flatMap2[A, B, C](s: ListMap[A, List[B]])(f: B => List[C]) : Map[A, List[C]] =
s.mapValues(_.flatMap(f))
scala> flatMap2(ListMap(2 -> List("a"), 1 -> List("c")))(x => List(x + "a"))
res4: scala.collection.immutable.Map[Int,List[String]] = Map(2 -> List(aa), 1 -> List(ca))
ListMap
此处保存原始订单。 mapValues
returns 查看 ListMap
,这也将保留顺序。
Scalaz 的幺半群可以帮助您向此类地图添加元素:
yourListMap |+| ListMap(key -> List(value))
scala> val map = ListMap(2 -> List("a"), 1 -> List("c"))
map: scala.collection.immutable.ListMap[Int,List[String]] = Map(2 -> List(a), 1 -> List(c))
scala> (map: Map[Int,List[String]]) |+| ListMap(1 -> List("b"))
res11: scala.collection.immutable.Map[Int,List[String]] = Map(2 -> List(a), 1 -> List(c, b))
您可以使用 Seq
而不是 List
,但是您将无法隐式转换为 semigroup。
给定以下代码:
def flatMap2[A, B, C](s:Seq[(A, B)])(f: B => Seq[C]) : Seq[(A, C)] =
s.flatMap { case (a, b) => f(b).map((a, _)) }
是否有更好的编码方式(也许在 scalaz 中退出)?
你能帮我找个更好的名字吗?
是否有更通用的抽象要使用 (Iterable
, TraversableOnce
)?
问题可能不清楚,此时我会说:
// s1: Seq[(A, B)], f: B => C
val s2: Seq[(A, C)] = s1.map((a, b) => a -> f(b))
这个怎么样:
import scala.collection.GenTraversable
import scala.collection.GenTraversableLike
import scala.collection.GenTraversableOnce
import scala.collection.generic.CanBuildFrom
implicit class WithMapFlatMapValues[A, B, Repr <: GenTraversable[(A, B)]](val self: GenTraversableLike[(A, B), Repr]) extends AnyVal {
def flatMapValues[C, That](f: B => GenTraversableOnce[C])(implicit bf: CanBuildFrom[Repr, (A, C), That]) = {
self.flatMap { case (a, b) => f(b).toIterator.map(a -> _) }
}
}
所以你可以这样做:
Vector("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))
// res1: Vector[(String, String)] = Vector((a,x), (b,x), (b,x))
Set("a"->1, "b"->2).flatMapValues(Iterator.tabulate(_)(_+"x"))
// res2: Set[(String, String)] = Set((a,0x), (b,0x), (b,1x))
你也可以用 Iterator 来做(这样你就涵盖了所有的 TraversableOnce):
implicit class WithMapFlatMapValuesItr[A, B](val self: Iterator[(A, B)]) extends AnyVal {
def flatMapValues[C](f: B => GenTraversableOnce[C]) = {
for { (a, b) <- self; c <- f(b).toIterator } yield (a -> c)
}
}
val i1 = Iterator("a"->1, "b"->2).flatMapValues(Seq.fill(_)("x"))
// i1: Iterator[(String, String)] = non-empty iterator
i1.toVector
// res6: Vector[(String, String)] = Vector((a,x), (b,x), (b,x))
看起来好一点:
def flatMap2[A, B, C](List[(A, B)])(f: B => Seq[C]) : List[(A, C)] =
for((a,b) <- s; bb <- f(b)) yield a -> bb
但是您在这里尝试做的事情更像是关于多映射(保留顺序),而不仅仅是元组序列:
def flatMap2[A, B, C](s: ListMap[A, List[B]])(f: B => List[C]) : Map[A, List[C]] =
s.mapValues(_.flatMap(f))
scala> flatMap2(ListMap(2 -> List("a"), 1 -> List("c")))(x => List(x + "a"))
res4: scala.collection.immutable.Map[Int,List[String]] = Map(2 -> List(aa), 1 -> List(ca))
ListMap
此处保存原始订单。 mapValues
returns 查看 ListMap
,这也将保留顺序。
Scalaz 的幺半群可以帮助您向此类地图添加元素:
yourListMap |+| ListMap(key -> List(value))
scala> val map = ListMap(2 -> List("a"), 1 -> List("c"))
map: scala.collection.immutable.ListMap[Int,List[String]] = Map(2 -> List(a), 1 -> List(c))
scala> (map: Map[Int,List[String]]) |+| ListMap(1 -> List("b"))
res11: scala.collection.immutable.Map[Int,List[String]] = Map(2 -> List(a), 1 -> List(c, b))
您可以使用 Seq
而不是 List
,但是您将无法隐式转换为 semigroup。