本文继续Scala讲座第七篇的第四部分内容,本部分提供了函数式编程的比较高阶一点的案例。

在学习完函数式编程的考虑办法之后,测验一下更高档的比如吧。这次考虑一下处理类似于XML的树结构数据的程序。既不运用循环也不运用变量如何来描绘杂乱的处理呢?

先出一个处理XML数据的标题。例如有如下的XML数据,有目录和文件,目录下有目录和文件两种元素。

标题的内容是从中取出文件的部分,并打印出文件名。程序的履行成果因该如下:

  1. file:aaa.txt
  2. file:bbb.txt
  3. file:ccc.txt
  4. file:ddd.txt

好,会变成怎样的程序呢?别的,Scala有十分强壮的XML处理功用,以上的功用实际上只需一两行程序就能够完成了。可是这次为了阐明函数式编程,特别不运用哪些功用,而运用简略功用来从头开端编码。

Scala中XML句子能够作为言语文本(Literal)像数字和字符串相同被处理。像下面这样

  1. scala>valxml=
  2. |
  3. |
  4. |
  5. |
  6. |
  7. |
  8. |
  9. |
  10. |
  11. xml:scala.xml.Elem=
  12. :(以下略)

没有双引号,一开端就写XML文本,然后将其赋值给变量(这儿是xml)。他的类型是Scala.xml.Elem,父类型为scala.xml.Node,表明XML的符号。在这儿包括在符号对中的内容被绑定在变量xml上。该Node类型里有名为child的办法,回来该符号的一切子元素。例如,这儿xml.child将回来以如下两个符号为成员的类似于ArrayBuffer的数组目标。

  1. :

这儿能够以为ArrayBuffer是列表相同的东西。进一步调用子元素的child办法则能够得到再下一层的元素。调用。标签目标的child办法将回来紧邻该标签的子元素(目录符号)。

仅运用这个办法该如何写获得文件名的程序呢?假设是面向目标办法,则能够首要界说Dir类和File类,然后界说Dir和File类的笼统父类Node,然后沿着树结构界说showFiles办法,然后递归调用该办法来获得文件名。也便是所谓的组合方式(图1)。

Scala讲座:函数式编程处理树结构数据(scala构造函数)  Scala讲座 函数式编程 Scala 第1张

Scala讲座 图1:组合方式

假设抛弃面向目标而考虑朴实的指令式办法的话就会很头疼了。由于只用for句子的话,关于每一个Dir都要用一个for循环,层次一多将会将会变得很杂乱,这儿省掉了指令式办法的完成。

接下来用函数式办法来考虑一下。函数式的情况下,由于考虑的是关于各个元素运用函数,先从***元素开端考虑运用什么函数。这个函数功用是“在某一时间回来某一元素下的文件列表”。这样就能够想到,那元素假设是file则可直接回来包括该file的列表,假设是Dir的话则回来包括一切子文件的列表。先来看看该函数的实例。

  1. deffileFinder(node:scala.xml.Node):List[scala.xml.Node]=node.labelmatch{
  2. case"xml"=>node.child.toList.flatMap(fileFinder)
  3. case"dir"=>node.child.toList.flatMap(fileFinder)
  4. case"file"=>List(node)
  5. case_=>List()
  6. }

其间toList()办法为将类列表目标(ArrayBuffer)转换为列表目标。方才用的是类似于ArrayBuffer类的目标,这儿将其转换为规范列表后再操作,而node.label则回来XML符号的称号。

这儿开端是正题了,除了file和无匹配处理(case _ => List())部分,xml和dir处理部分是问题的要害,也便是node.child.toList.flatMap(fileFinder)部分。假设这儿重视的是Node目标,那处理进程因该是这样的,首要用child办法取出Node的一切子元素,然后用前面阐明过的类似于map的函数对每一个子元素运用fileFinder办法并递归重复这一进程。那为什么这样编码之后就能得到Node下的一切file元素了呢?

那么flatMap本来的功用又是什么呢?让我们将其转换成map函数,然后看一下履行进程。将XML的结构简略化之后将如下所示

  1. ←这儿

假设现在的要素方位是xml符号,将其子元素转换成列表后对其各个项目运用函数。

  1. List(fileFinder(~),fileFinder())

file的话坚持原样,假设是dir则对其子元素运用函数。

  1. List(List(fileFinder(~),fileFinder()),List())

接着关于***个Node元素运用函数。

  1. List(List(List(,),List()),List())

了解上述作业进程是比较困难的,重要的是在我的脑中考虑的并不是这样杂乱的逻辑,而仅仅是完成“从一个Node元素中取出file列表”的函数的逻辑。这需求必定程度的思路切换,考虑用指令式办法来完成时实际上花了我2-3小时,而想到这个函数式办法后不到10分钟就想通了。

感觉上如同现已完成了,可是这还不行。方才用map来设想的进程完成后,得到的是List里边还有List的一个复合结构,光这样还不能被运用。那么,flatMap函数就进场了。这个函数在Scala的机制上具有同map函数平等的重要层度,将map和flatMap说成Scala函数机制的中心都不为过火。

“flatMap “函数对每一个元素运用函数参数之后将其成果以列表方式回来,这时回来成果是列表类型是要害。接着看一下简略的比如吧

首要是map函数的比如。关于内容为“1,2,3,4,5 “的列表,运用x*2函数。

  1. file:aaa.txt
  2. file:bbb.txt
  3. file:ccc.txt
  4. file:ddd.txt
0

成果是List(2, 4, 6, 8, 10),行将每一个元素乘以2。题外话,还有一个叫做filter的函数,他回来过滤成果。

  1. file:aaa.txt
  2. file:bbb.txt
  3. file:ccc.txt
  4. file:ddd.txt
1

也便是,3以外的情况下使元素值翻倍,3的时分将元素分割为“3.1, 3.2, 3.3“。因而,表面上关于List(1,2,3,4,5)适用该函数后期望回来的是List(1, 2,

转载请说明出处
知优网 » Scala讲座:函数式编程处理树结构数据(scala构造函数)

发表评论

您需要后才能发表评论