【转】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]



如果不了解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的东西,虽然因为复杂对于这个库有些负面的声音,

但它的确提供了一些很棒的特性。

package test.scala.lang

object TestMap {

  def main(args: Array[String]): Unit = {
    testReduce
  }

  def test = {
    val t = Seq("a", "b", "c", "d")
    println("println t")
    t.foreach { e => println(e) }
    val r1 = t.map { e => e.toUpperCase() }
    println("println r1")
    r1.foreach { e => println(e) }

    val r2 = t.map { _.toUpperCase() }
    println("println r2")
    r2.foreach { e => println(e) }
  }

  def testFlatmap = {
    val t = Seq("a", "b", "c", "d")
    println("println t")
    t.foreach { e => println(e) }
    val r1 = t.flatMap { x => ulcase(x) }
    println("println r1")
    r1.foreach { e => println(e) }
  }

  def ulcase(s: String) = Vector(s.toUpperCase(), s.toLowerCase())

  def testZip = {
    val t1 = "Hello.World".toCharArray
    val t2 = 1 to 20 toArray

    val r1 = t1.zip(t2)
    println("println r1")
    r1.foreach { e => println(e) }

    val r2 = t2.zip(t1)
    println("println r2")
    r2.foreach { e => println(e) }

    val r3 = t2.zip(t2)
    println("println r3")
    r3.foreach { e => println(e) }

  }

  def testReduce = {
    val t = 1 to 20 toList
    val r1 = t.reduce(sum)
    println("r1=" + r1)

    val r2 = t.reduceLeft(sum)
    println("r2=" + r2)

    val r3 = t.reduceRight(sum)
    println("r3=" + r3)
  }

  def sum(x: Int, y: Int): Int = { println(x, y); x + y }
}

  

时间: 2024-08-19 14:10:52

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

SparkContext, map, flatMap, zip以及例程wordcount

SparkContext 通常作为入口函数,可以创建并返回一个RDD. 如把Spark集群当作服务端那Spark Driver就是客户端,SparkContext则是客户端的核心: 如注释所说 SparkContext用于连接Spark集群.创建RDD.累加器(accumlator).广播变量(broadcast variables) map操作: 会对每一条输入进行指定的操作,然后为每一条输入返回一个对象: flatMap操作: "先映射后扁平化" 操作1:同map函数一样:对每一条

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

http://www.ituring.com.cn/article/131442 https://twitter.github.io/scala_school/zh_cn/collections.html#flatten 如果不了解map,flatMap,zip和reduce函数,你就不能真正地谈论scala.通过这些函数,我们可以非常容易地处理列表的内容并结合Option对象工作.你可以在这个站点找到更多的片段:Scala片段 1:FoldingScala 片段2:List的操作符魔法 让我们

Scala learning(2): map, flatMap, filter与For表达式

本文叙述Collections里最常见的三种操作map, flatMap, filter,与For表达式的关系. List对三种方法的实现 map在List的实现: abstract class List[+T] { def map[U](f: T => U): List[U] = this match { case x :: xs => f(x) :: xs.map(f) case Nil => Nil } } flatMap在List的实现: abstract class List[

python几个重要的函数(lambda,filter,reduce,map,zip)

一.匿名函数lambda lambda argument1,argument2,...argumentN :expression using arguments 1.lambda是一个表达式,而不是一个语句. 因为这一点,lambda可以出现在python语法不允许def出现的地方---例如,在一个列表常量中或者函数调用的参数中,此外,作为一个表达式,lambda返回一个值一个值(一个新的函数),可以选择性地值给一个变量名.相反,def语句总是得在头部将一个新的函数赋值给一个变量名,而不是将这个

Swift函数编程之Map、Filter、Reduce

在Swift语言中使用Map.Filter.Reduce对Array.Dictionary等集合类型(collection type)进行操作可能对一部分人来说还不是那么的习惯.对于没有接触过函数式编程的开发者来说,对集合类型中的数据进行处理的时候第一反应可能就是采用for in遍历.本文将介绍一些Swift中可以采用的新方法. Map Map函数会遍历集合类型并对其中的每一个元素进行同一种的操作.Map的返回值是一个所得结果的数组.例如:我们要对一个数组里面的数据进行平方操作,常见的代码如下:

C#数组的Map、Filter、Reduce等价方法

在Javascript.Python等语言里,Map.Filter和Reduce是数组的常用方法,可以让你在实现一些数组操作时告别循环,具有很高的实用价值.它们三个的意义大家应该都清楚,有一个十分形象的解释如下: 然而,支持lambda表达式的C#也有类似的方法,但不是这样命名的.实现IEnumerable接口的类(如List.HashSet.继承Array的类等)都有如下等价方法: “Map” => Select方法 “Filter” => Where方法 “Reduce” => Ag

使用python实现内置map,filter,reduce函数

map函数 # -*- coding: cp936 -*- def myselfmap(f,*args):     def urgymap(f,args):         if args==[]:             return []         else:             return [f(args[0])]+urgymap(f,args[1:])     if list(args)[0]==[]:             #*args有多个参数被传递时返回tuple  

Swift高阶函数:Map,Filter,Reduce

闭包介绍 Swift一大特性便是使用简洁的头等函数/闭包语法代替了复杂的blocks语法.希望我们在Swift中不再需要像fuckingblocksyntax中所描述的语法.(译者注:头等函数-即可将函数当作参数传递给其他的函数,或从其他的函数里返回出值,并且可以将他们设定为变量,或者将他们存储在数据结构中) 闭包是自包含的blocks,它能在代码中传递和使用. 本文我们将重点介绍匿名定义的闭包(如:定义成内联的且不具名)也称匿名闭包.我们能够将其作为参数传递给其他函数/方法或者将其作为返回值.

Python的map、filter、reduce函数

python提供了map.filter.reduce三个函数,用于对一整组输入进行统一处理. map:映射,对一整组输入中的每个值进行一个函数计算,输出每个值对应的结果. filter:过滤,输入的函数必须有一个返回值True或者False,filter只会把经过函数处理后结果是True的值输出. reduce:归纳,会对所有输入运用一个函数,返回一个输出. 例子: def even(x): return x%2==True map(even,range(4)) =>[True,False,Tr