如何简化嵌套的地图调用?
How to simplify nested map calls?
假设我有一些嵌套仿函数,例如List[Option[Int]]
需要调用最里面的map
。
现在我正在使用嵌套 maps
:
scala> val opts: List[Option[Int]] = List(Some(0), Some(1))
opts: List[Option[Int]] = List(Some(0), Some(1))
scala> opts.map(o => o.map(_ + 1))
res0: List[Option[Int]] = List(Some(1), Some(2))
例如,如果我有 3 个嵌套级别怎么办?
嵌套 maps
是否有任何简单的替代方法?
从问题中我了解到您正在尝试修剪列表迭代器 e.i。删除上层列表,在这种情况下,您可以使用 flatten
将列表列表转换为单个列表。
我将使用 flatten
删除几层列表
代码:-
val lists = List(
List(
List(
List("1"),List("2")
),
List(
List("3"),List("4")
) ,
List(
List("a"),List("b")
),
List(
List("c"),List("d")
)
)
)
val innerVal = lists.flatten.foreach(println)
结果:-
List(List(1), List(2))
List(List(3), List(4))
List(List(a), List(b))
List(List(c), List(d))
如果你有很多嵌套的仿函数并且你不想将它们展平(即它们不是单子或者你不想将它们用作单子) - 那么镜头可能会有所帮助。有 quicklens 实现,支持可移动镜头:http://www.warski.org/blog/2015/03/quicklens-traversing-options-and-lists/。
示例(抱歉没有尝试编译它):
modify(opts)(_.each.each).using(_ + 1)
无论如何,你必须指定嵌套级别,但你不必在这里嵌套函数。而且指定一次就够了,比如(概念示例,没查):
def md2[T]: (l: List[Option[T]]) => modify(l)(_.each.each)
md2[Int](opts).using(_ + 1)
是的,这可以通过 scalaz.Functor:
scala> import scalaz.Functor
import scalaz.Functor
scala> import scalaz.std.list._
import scalaz.std.list._
scala> import scalaz.std.option._
import scalaz.std.option._
scala> Functor[List].compose[Option].map(List(some(0), some(1)))(_ + 1)
res1: List[Option[Int]] = List(Some(1), Some(2))
但是,这比使用嵌套 map
简单地调用 map
要长。如果经常映射嵌套结构,可以创建辅助函数:
def map2[F[_], G[_], A, B](fg: F[G[A]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G]): F[G[B]] =
F0.map(fg)(g => G0.map(g)(f))
def map3[F[_], G[_], H[_], A, B](fg: F[G[H[A]]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G], H0: Functor[H]): F[G[H[B]]] =
F0.map(fg)(g => G0.map(g)(h => H0.map(h)(f)))
...
用法:
scala> map2(List(some(0), some(1)))(_ + 1)
res3: List[Option[Int]] = List(Some(1), Some(2))
scala> map3(List(some(some(0)), some(some(1))))(_ + 1)
res4: List[Option[Option[Int]]] = List(Some(Some(1)), Some(Some(2)))
假设我有一些嵌套仿函数,例如List[Option[Int]]
需要调用最里面的map
。
现在我正在使用嵌套 maps
:
scala> val opts: List[Option[Int]] = List(Some(0), Some(1))
opts: List[Option[Int]] = List(Some(0), Some(1))
scala> opts.map(o => o.map(_ + 1))
res0: List[Option[Int]] = List(Some(1), Some(2))
例如,如果我有 3 个嵌套级别怎么办?
嵌套 maps
是否有任何简单的替代方法?
从问题中我了解到您正在尝试修剪列表迭代器 e.i。删除上层列表,在这种情况下,您可以使用 flatten
将列表列表转换为单个列表。
我将使用 flatten
代码:-
val lists = List(
List(
List(
List("1"),List("2")
),
List(
List("3"),List("4")
) ,
List(
List("a"),List("b")
),
List(
List("c"),List("d")
)
)
)
val innerVal = lists.flatten.foreach(println)
结果:-
List(List(1), List(2))
List(List(3), List(4))
List(List(a), List(b))
List(List(c), List(d))
如果你有很多嵌套的仿函数并且你不想将它们展平(即它们不是单子或者你不想将它们用作单子) - 那么镜头可能会有所帮助。有 quicklens 实现,支持可移动镜头:http://www.warski.org/blog/2015/03/quicklens-traversing-options-and-lists/。
示例(抱歉没有尝试编译它):
modify(opts)(_.each.each).using(_ + 1)
无论如何,你必须指定嵌套级别,但你不必在这里嵌套函数。而且指定一次就够了,比如(概念示例,没查):
def md2[T]: (l: List[Option[T]]) => modify(l)(_.each.each)
md2[Int](opts).using(_ + 1)
是的,这可以通过 scalaz.Functor:
scala> import scalaz.Functor
import scalaz.Functor
scala> import scalaz.std.list._
import scalaz.std.list._
scala> import scalaz.std.option._
import scalaz.std.option._
scala> Functor[List].compose[Option].map(List(some(0), some(1)))(_ + 1)
res1: List[Option[Int]] = List(Some(1), Some(2))
但是,这比使用嵌套 map
简单地调用 map
要长。如果经常映射嵌套结构,可以创建辅助函数:
def map2[F[_], G[_], A, B](fg: F[G[A]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G]): F[G[B]] =
F0.map(fg)(g => G0.map(g)(f))
def map3[F[_], G[_], H[_], A, B](fg: F[G[H[A]]])(f: A => B)
(implicit F0: Functor[F], G0: Functor[G], H0: Functor[H]): F[G[H[B]]] =
F0.map(fg)(g => G0.map(g)(h => H0.map(h)(f)))
...
用法:
scala> map2(List(some(0), some(1)))(_ + 1)
res3: List[Option[Int]] = List(Some(1), Some(2))
scala> map3(List(some(some(0)), some(some(1))))(_ + 1)
res4: List[Option[Option[Int]]] = List(Some(Some(1)), Some(Some(2)))