map,flatMap,zip和reduce函數可以讓我們更容易處理列表函數。
1 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)
2 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)
flatMap還可以看作是flatten和map兩種的結合
flatten將嵌套結構扁平化為一個層次的集合
scala> List(List(1, 2), List(3, 4)).flatten res0: List[Int] = List(1, 2, 3, 4)
scala> val nestedNumbers = List(List(1, 2), List(3, 4)) nestedNumbers: List[List[Int]] = List(List(1, 2), List(3, 4)) scala> nestedNumbers.flatMap(x => x.map(_ * 2)) res0: List[Int] = List(2, 4, 6, 8) //等價於 scala> nestedNumbers.map((x: List[Int]) => x.map(_ * 2)).flatten res1: List[Int] = List(2, 4, 6, 8)
3 zip函數
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))
4 reduce函數
使用reduce我們可以處理列表的每個元素並返回一個值。通過使用reduceLeft和reduceRight我們可以強制處理元素的方向。(使用reduce方向是不被保證的)
注:reduce和fold很像,但reduce返回的值的類型必須和列表的元素類型相關(類型本身或其父類),但fold沒有這種限制(但與此同時fold必須給定一個初始值),可以說reduce是fold的一種特殊情況。
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
參考資料
ttp://www.ituring.com.cn/article/131442
https://twitter.github.io/scala_school/zh_cn/collections.html#flatten
