微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

scala – 这个递归列表如何平坦化?

Scala邮件列表之后的一个 this was asked and answered

凯文:

Given some nested structure: List[List[...List[T]]]
what’s the best (preferably type-safe) way to flatten it to a List[T]

加斯帕:

A combination of implicits and default arguments works:

case class Flat[T,U](fn : T => List[U]) 

implicit def recFlattenFn[T,U](implicit f : Flat[T,U] = Flat((l : T) 
=> List(l))) = 
   Flat((l : List[T]) => l.flatMap(f.fn)) 

def recFlatten[T,U](l : List[T])(implicit f : Flat[List[T],U]) = f.fn(l)

例子:

scala> recFlatten(List(1,2,3)) 
res0: List[Int] = List(1,3) 

scala> recFlatten(List(List(1,3),List(4,5))) 
res1: List[Int] = List(1,3,4,5) 

scala> recFlatten(List(List(List(1,5)),List(List(6,7)))) 
res2: List[Int] = List(1,5,6,7)

我一直在看这个代码一段时间.我不知道它是如何工作的.似乎有一些递归涉及…有人可以散发光吗?这个模式有其他的例子,它有一个名字吗?

解决方法

哦,哇,这是一个老的!我将首先清理代码,并将其与现行惯用惯例相一致:

case class Flat[T,U](fn: T => List[U]) 

implicit def recFlattenFn[T,U](
  implicit f: Flat[T,U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)

def recFlatten[T,U](xs: List[T3])(implicit f: Flat[List[T],U]) = f fn xs

然后,不用多说,分解代码.首先,我们有Flat类:

case class Flat[T,U](fn: T => List[U])

这只不过是函数T =>的命名包装器列表[U],当给定一个类型为T的实例时,将构建一个List [U]的函数.请注意,这里的T也可以是List [U]或U,或List [List [List [U] ]]等.通常,这样的函数可以直接指定为参数的类型.但是我们将使用这个隐含的,所以命名的包装器避免任何隐含冲突的风险.

然后,从recFlatten向后工作:

def recFlatten[T,U](xs: List[T])(implicit f: Flat[List[T],U]) = f fn xs

方法将采用xs(List [T])并将其转换为U.为了实现这一点,它定位了一个隐含的Flat [T,U]实例,并调用附带的函数fn

然后,真正的魔法:

implicit def recFlattenFn[T,U] = Flat((xs: T) => List(xs))
) = Flat((xs: List[T]) => xs flatMap f.fn)

这满足recFlatten所需的隐式参数,它也需要另一个隐式参数.最关键的是

> recFlattenFn可以作为自己的隐式参数
>它返回一个Flat [List [X],X],所以recFlattenFn只会被隐式解析为Flat [T,U],如果T是一个列表
>如果隐式解析失败(即T不是列表),隐式f可以回退到认值

也许这在一个例子的上下文中是最好的理解的:

recFlatten(List(List(1,5)))

>类型T推断为List [List [Int]]
对于’Flat [List [List [Int]],尝试进行隐式查找
>这被一个递归定义的recFlattenFn匹配

一般来说:

recFlattenFn[List[List[Int]],U] ( f =
  recFlattenFn[List[Int],U] ( f =
    Flat[Int,U]((xs: T) => List(xs)) //default value
  )
)

请注意,recFlattenFn将仅匹配Flat [List [X],X]和类型参数[Int,_]在此匹配中失败的隐含搜索,因为Int不是列表.这是什么触发回退到认值.

类型推断也可以向上运行该结构,在每个递归级别解析U参数:

recFlattenFn[List[List[Int]],Int] ( f =
  recFlattenFn[List[Int],Int] ( f =
    Flat[Int,Int]((xs: T) => List(xs)) //default value
  )
)

这只是一个平面实例的嵌套,每个(最内层除外)执行一个flatMap操作来展开嵌套列表结构的一个层次.最内层的Flat简单地将所有的单个元素包装在单个列表中.

证明完毕

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐