目录
正文
函数式编程对集合操作有一些通行的“叫法”,或者更像是一些“俚语”,它们的含义清晰明确,但是很难顾名思义,比如常见的“filter”,”map”,”flatMap”,“redue”等等。本文会把一些主要“俚语”详细地解释一下,同时给出一些参考示例。
设定一个判定结果为布尔型的过滤条件,应用到集合的每一个元素上,返回的是集合里所有满足条件的元素构成的一个子集。
scala> List.range(1, 11).filter (_ % 3 == 0)
res1: List[Int] = List(3, 6, 9)
scala> List("the", "quick", "brown", "fox", "jumped","over", "the", "lazy", "dog").filter(_.length == 3)
res2: List[String] = List(the, fox, the, dog)
filter类型操作的一个变种,同样是设定一个判定结果为布尔型的过滤条件,应用到集合的每一个元素上,返回的是二个元素的Tuple, 第一个元素是所有满足条件的元素构成一个集合,第二个元素是所有不满足条件的元素构成一个集合。
scala> List.range(1, 11).partition(_ % 3 == 0)
res3: (List[Int], List[Int]) = (List(3, 6, 9),List(1, 2, 4, 5, 7, 8, 10))
filter类型操作的一个变种,同样是设定一个判定结果为布尔型的过滤条件,返回集合中满足条件的第一个元素。
scala> List.range(1, 11).find(_ % 3 == 0)
res4: Option[Int] = Some(3)
filter类型操作的一个变种,同样是设定一个判定结果为布尔型的过滤条件,从集合的第一个元素开始,逐一判定元素是否符合条件,在遇到第一个不符合条件的元素后随即结束过滤,返回的结果就是集合中前N个连续满足条件的元素。
scala> List(1, 2, 3, -4, 5, 6, 7, 8, 9, 10) takeWhile (_ > 0)
res5: List[Int] = List(1, 2, 3)
设定一个针对元素的“转换”操作,应用到集合的每一个元素上,返回的结果是每个元素被转换之后的新值组成的新集合。新的集合与旧集合大小一样,但元素都是更新的,甚至类型也会发生变化。
scala> List(1, 2, 3, 4, 5) map (_ + 1)
res6: List[Int] = List(2, 3, 4, 5, 6)
scala> List("the", "quick", "brown", "fox", "jumped","over", "the", "lazy", "dog").map(_.length)
res7: List[Int] = List(3, 5, 5, 3, 6, 4, 3, 4, 3)
对于嵌套的集合(即集合中的元素还是集合),如果我们希望把每一个嵌套的子集“转换”成一个新的子集,这时候就应该使用flatMap。
flatMap,不单单应用于集合,它代表着一种很普遍的操作:对于某种嵌套的数据结构,如果它的某个操作会把它的嵌套元素转化或产生出新嵌套元素,则最终产生的将是一个“二维”的数据结构,也就是嵌套元素本身也是一个嵌套元素,这通常会让这个产出的结果很不好用,一个必备的工作就是把这个二维”的数据结构“压平”,重新拼接成一个一维的结构,这正是flatMap要做的事情。所以除了集合,Future也有这个方法,它就是在你使用map去转换它的underlying时返回的又恰巧是一个Future,那么这时你可以使用flatMap进行扁平化处理,得到的还是一个Future,而不是Future嵌套着Future。
scala> List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) flatMap (_.toList)
res2: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) flatMap (_.reverse)
res3: List[Int] = List(3, 2, 1, 6, 5, 4, 9, 8, 7)
要特别注意的是flatMap使用的函数参数接收的是一个集合,返回的也是一个集合(GenTraversableOnce
),你不能将一个集合元素“转换”成单一的值,比如,你不能这样做:
scala> List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) flatMap (_ + 1)
:12: error: type mismatch;
found : Int(1)
required: String
List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) flatMap (_ + 1)
^
如果你想针对嵌套集合中的每个元素进行装换得到一个统一的集合,你可以这做做:
scala> List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) flatMap (_.map(_+1))
res10: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9, 10)
下面是一个flatMap更加直观的例子:
在函数式编程里经常会出现嵌套的集合,我们需要频繁地把这种嵌套的结构”压“成”扁平“的单一集合,这个动作在函数式编程里叫”flatten”。即:将所有嵌套的集合的元素一一取出逐一放置到一个集合中。
scala> List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)).flatten
res12: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> List("the", "quick", "brown", "fox", "jumped","over", "the", "lazy", "dog").flatten
res13: List[Char] = List(t, h, e, q, u, i, c, k, b, r, o, w, n, f, o, x, j, u, m, p, e, d, o, v, e, r, t, h, e, l, a, z, y, d, o, g)
如果我们把集合看成是一张纸条,每一小段代表一个元素,那么reduceLeft就将这张纸条从左向右”折叠”,最前面的两个元素会首先“重叠”在一起,这时会使用传给reduceLeft的参数函数进行计算,返回的结果就像是已经折叠在一起的两段纸条,它们已经是一个叠加的状态了,所以它,也就是上次重叠的结果会继续做为一个单一的值和下一个元素继续“叠加”,直到折叠到集合的最后一个元素。
scala> List.range(1, 10).reduceLeft(_+_)
res0: Int = 45
同理,reduceRight就将这张纸条从右向左”折叠”。要留心reduceRight的地方时:它的操作方向是从右到左,但是参数的顺序却并不是,而是依然第一参数是左边的元素,第二参数是右边的元素。我们可以通过一个示例来验证:
List.range(1, 10) reduceRight(_ - _)
// 8 - 9 = -1
// 7 - (-1) = 8
// 6 - 8 = -2
// 5 - (-2) = 7
// 4 - 7 = -3
// 3 - (-3) = 6
// 2 - 6 = -4
// 1 - (-4) = 5
// result: 5
与reduceLeft极为相似,只是它开始操作的第一个元素是以参数的形式传入的,而不是集合的第一个元素。
scala> List.range(1, 10).foldLeft(1)(_+_)
res1: Int = 46
与reduceRight极为相似,只是它开始操作的第一个元素是以参数的形式传入的,而不是集合的最后一个元素。
scala> List.range(1, 10).foldRight(5)(_ - _)
res8: Int = 0
本文原文出处: http://blog.csdn.net/bluishglc/article/details/53320654 转载请注明出处。