(转)scala学习笔记(8): 列表的map,flatMap,zip和reduce

http://www.ituring.com.cn/article/131442

https://twitter.github.io/scala_school/zh_cn/collections.html#flatten

如果不了解mapflatMapzipreduce函数,你就不能真正地谈论scala。通过这些函数,我们可以非常容易地处理列表的内容并结合Option对象工作。你可以在这个站点找到更多的片段:
Scala片段 1:Folding
Scala 片段2:List的操作符魔法

让我们从map开始,通过map我们可以将一个函数应用于列表的每一个元素并且将其作为一个新的列表返回。
我们可以这样对列表的元素进行平方:

scala> list1
res3: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> list1.map(x=>x*x)
res4: List[Int] = List(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100)

一些函数可能返回Option元素。例如:

scala> val evenify = (x:Int) => if (x % 2 == 0) Some(x) else None
evenify: Int => Option[Int] = <function1>

scala> list1.map(evenify)
res6: List[Option[Int]] = List(Some(0), None, Some(2), None, Some(4), None, Some(6), None, Some(8), None, Some(10))

这个例子的问题是我们常常并不关心None。但我们怎么轻松地把他排除出去呢?对于此我们可以使用flatMap。通过flatMap我们可以处理元素是序列的列表。将提供的函数应用于每个序列元素会返回包含原始列表所有序列内的元素的列表。通过以下的例子会更好理解:

scala> val list3 = 10 to 20 toList
list3: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)

scala> val list2 = 1 to 10 toList
list2: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val list4 = List(list2, list3)
list4: List[List[Int]] = List(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20))

scala> list4.flatMap(x=>x.map(y=>y*2))
res2: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40)

我们可以看到有list4的元素是两个列表。我们调用flatMap分别处理这两个列表,并用map将这两个列表的元素平方,最后的结果是一个包含所有元素的平坦的列表。

译者注:flatMap并不一定用于元素是序列的列表,他只需要应用的函数返回的结果是GenTraversableOnce即可(列表的父类),例如:

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

scala> res0.flatMap(x => 1 to x )
res1: List[Int] = List(1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5)

让我们回过头看一下一直看过的evenify函数和之前返回的Option列表:

scala> val list1 = 1 to 10 toList
list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> list1.map(evenify)
res3: List[Option[Int]] = List(None, Some(2), None, Some(4), None, Some(6), None, Some(8), None, Some(10))

scala> val list2 = list1.map(evenify)
list2: List[Option[Int]] = List(None, Some(2), None, Some(4), None, Some(6), None, Some(8), None, Some(10))

scala> list2.flatMap(x => x)
res6: List[Int] = List(2, 4, 6, 8, 10)

简单吧。我们也可以将这个写在一行:

scala> list1.flatMap(x=>evenify(x))
res14: List[Int] = List(2, 4, 6, 8, 10)

正如你看到的,这并不困难。接下来让我们看一下其他两个可以用于列表的函数。第一个是zip,从它的名字就可以知道我们可以用此合并两个列表:

scala> val list = "Hello.World".toCharArray
list: Array[Char] = Array(H, e, l, l, o, ., W, o, r, l, d)

scala> val list1 = 1 to 20 toList
list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)

scala> list.zip(list1)
res30: Array[(Char, Int)] = Array((H,1), (e,2), (l,3), (l,4), (o,5), (.,6), (W,7), (o,8), (r,9), (l,10), (d,11))

scala> list1.zip(list)
res31: List[(Int, Char)] = List((1,H), (2,e), (3,l), (4,l), (5,o), (6,.), (7,W), (8,o), (9,r), (10,l), (11,d))

返回的列表长度取决于较短的列表,只要有一个列表到达了末尾zip函数就停止了。我们可以使用zipAll函数来对较长列表的剩余元素进行处理:

scala> list.zipAll(list1,‘a‘,‘1‘)
res33: Array[(Char, AnyVal)] = Array((H,1), (e,2), (l,3), (l,4), (o,5), (.,6), (W,7), (o,8), (r,9), (l,10), (d,11), (a,12), (a,13), (a,14), (a,15), (a,16), (a,17), (a,18), (a,19), (a,20))
(译者注:最后一个参数为1,让返回类型是Array[(Char,Int)]对于这个例子更好点)

如果字母的列表比较短,那么用‘a‘来补充,反之用1来补充。最后一个要介绍的zip函数是zipWithIndex。就像他的名字一样,元素的下标(从0开始)会被增加进去:

scala> list.zipWithIndex
res36: Array[(Char, Int)] = Array((H,0), (e,1), (l,2), (l,3), (o,4), (.,5), (W,6), (o,7), (r,8), (l,9), (d,10))

我们来看看最后一个函数:reduce。使用reduce我们可以处理列表的每个元素并返回一个值。通过使用reduceLeftreduceRight我们可以强制处理元素的方向。(使用reduce方向是不被保证的)
译者注:reducefold很像,但reduce返回的值的类型必须和列表的元素类型相关(类型本身或其父类),但fold没有这种限制(但与此同时fold必须给定一个初始值),可以说reducefold的一种特殊情况。

scala> list1
res51: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)

scala> val sum = (x:Int, y:Int) => {println(x,y) ; x + y}
sum: (Int, Int) => Int = <function2>

scala> list1.reduce(sum)
(1,2)
(3,3)
(6,4)
(10,5)
(15,6)
(21,7)
(28,8)
(36,9)
(45,10)
(55,11)
(66,12)
(78,13)
(91,14)
(105,15)
(120,16)
(136,17)
(153,18)
(171,19)
(190,20)
res52: Int = 210

scala> list1.reduceLeft(sum)
(1,2)
(3,3)
(6,4)
(10,5)
(15,6)
(21,7)
(28,8)
(36,9)
(45,10)
(55,11)
(66,12)
(78,13)
(91,14)
(105,15)
(120,16)
(136,17)
(153,18)
(171,19)
(190,20)
res53: Int = 210

scala> list1.reduceRight(sum)
(19,20)
(18,39)
(17,57)
(16,74)
(15,90)
(14,105)
(13,119)
(12,132)
(11,144)
(10,155)
(9,165)
(8,174)
(7,182)
(6,189)
(5,195)
(4,200)
(3,204)
(2,207)
(1,209)
res54: Int =210

对于这个片段来说这些就足够了,是时候你自己探索一下List/Collections的API了。在下一个片段中,我们将看一些Scalaz的东西,虽然因为复杂对于这个库有些负面的声音,但它的确提供了一些很棒的特性。

时间: 2024-10-13 11:47:42

(转)scala学习笔记(8): 列表的map,flatMap,zip和reduce的相关文章

【转】Scala 片段3:列表的map,flatMap,zip和reduce

原文链接 http://www.ituring.com.cn/article/131442 本文翻译自:Scala snippets 3: Lists together with Map, flatmap, zip and reduce [email protected] 如果不了解map,flatMap,zip和reduce函数,你就不能真正地谈论scala. 通过这些函数,我们可以非常容易地处理列表的内容并结合Option对象工作. 你可以在这个站点找到更多的片段: Scala片段 1:Fo

Scala学习笔记及与Java不同之处总结-从Java开发者角度

Scala与Java具有很多相似之处,但又有很多不同.这里主要从一个Java开发者的角度,总结在使用Scala的过程中所面临的一些思维转变. 这里仅仅是总结了部分两种语言在开发过程中的不同,以后会陆续更新一些切换后在开发过程中值得注意的地方.以下列举了部分,但令人印象深刻的Scala语言的不同之处,具体的代码演示样例及具体阐述见下文. ? Scala中可直接调用Java代码,与Java无缝连接. 语句能够不用";"结束.且推荐不适用";". 变量声明时以var或va

Scala学习笔记及与Java不同之处总结-从Java开发人员角度

Scala与Java具有许多相似之处,但又有许多不同.这里主要从一个Java开发人员的角度,总结在使用Scala的过程中所面临的一些思维转变.这里只是总结了部分两种语言在开发过程中的不同,以后会陆续更新一些切换后在开发过程中值得注意的地方.下面列举了部分,但令人印象深刻的Scala语言的不同之处,具体的代码示例及详细阐述见下文. ? Scala中可直接调用Java代码,与Java无缝连接: 语句可以不用";"结束,且推荐不适用";": 变量声明时以var或val开头

Scala学习笔记一之基础语法,条件控制,循环控制,函数,数组,集合

前言:Scala的安装教程:http://www.cnblogs.com/biehongli/p/8065679.html 1:Scala之基础语法学习笔记: 1:声明val变量:可以使用val来声明变量,用来存放表达式的计算结果,但是常量声明后是无法改变它的值的,建议使用val来声明常量: 声明var变量:如果要声明可以改变的引用,可以使用var变量,声明的常量的值可以改变. 3:指定类型:无论声明val变量还是声明var变量.都可以手动指定其类型,如果不指定,scala会自动根据值,进行类型

原创:Scala学习笔记(不断更新)

Scala是一种函数式语言和面向对象语言结合的新语言,本笔记中就零散记下学习scala的一些心得,主要侧重函数式编程方面. 1. 以递归为核心控制结构. 实现循环处理的方式有三种:goto,for/while,递归,其中用goto实现循环已经在现代语言中被放弃,而for/while形式的结构化编程成为主流,而递归作为另一种方案,则长期只流行在函数式编程的小圈子中. 递归被主流编程界所担心的主要是过深的调用栈,甚至以前的课堂上我们还亲自尝试过将递归改写为循环,但是现代函数式编程语言中,通过尾递归(

Scala学习笔记(一)编程基础

强烈推荐参考该课程:http://www.runoob.com/scala/scala-tutorial.html 1.   Scala概述 1.1.  什么是Scala Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性.Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序. 1.2.  为什么要学Scala 1.优雅:这是框架设计师第一个要考虑的问题,框架的用户是应用开发程序员,API是否优雅直接影响用户体验. 2.速度快:Scala

scala学习笔记一

Scala是数据挖掘算法领域最有力的编程语言之一,语言本身是面向函数,这也符合了数据挖掘算法的常用场景:在原始数据集上应用一系列的变换,语言本身也对集合操作提供了众多强大的函数,本文将以List类型为例子,介绍常见的集合变换操作. 一.常用操作符(操作符其实也是函数) ++ ++[B](that: GenTraversableOnce[B]): List[B] 从列表的尾部添加另外一个列表 ++: ++:[B >: A, That](that: collection.Traversable[B]

Scala学习笔记(1)

为什么选择Scala? 表达能力 函数是一等公民 闭包 简洁 类型推断 函数创建的文法支持 Java 可重用java库 可重用java工具 没有性能惩罚 Scala如何工作? 编译成Java字节码 可在任何标准JVM上运行 甚至是在一些不规范的JVM上,如Dalvik Scala编译器是Java编译器的作者写的 下载和安装 可以在http://www.scala-lang.org/上下载最新的scala安装包.下载后解压,然后切换到scala所在目录,执行: $ cd /export/scala

Programming in scala学习笔记(二)Next steps in scala

1 声明一个数组 Java的string数组声明如下: String[] greetStrings = new String()[4]; 数组索引跟java和c++/c语言不一样的是不用"[ ]",用"( )". 也可以用比较繁琐的方式声明数组: greetStrings是val常量,只能指向同一个Array对象,但是,greetStrings(0-2)的值是可变的. 2. 关于数组为什么不用"[ ]",用"( )" Arra