Scala 片段3:列表的map,flatMap,zip和reduce
本文翻譯自:Scala snippets 3: Lists together with Map, flatmap, zip and reduce
fairjm@ituring
如果不瞭解map
,flatMap
,zip
和reduce
函式,你就不能真正地談論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
我們可以處理列表的每個元素並返回一個值。通過使用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
對於這個片段來說這些就足夠了,是時候你自己探索一下List
/Collections
的API了。在下一個片段中,我們將看一些Scalaz
的東西,雖然因為複雜對於這個庫有些負面的聲音,但它的確提供了一些很棒的特性。
相關文章
- lambda map filter reduce zip 以及列表推導Filter
- Swift集合函式:Reduce、Map、FlatMap、FilterSwift函式Filter
- Scala中的Map、Tuple、Zip
- Java,Pyhon,Scala比較(一)map,reduceJava
- Python學習筆記 - filter,map,reduce,zipPython筆記Filter
- python常用函式進階(2)之map,filter,reduce,zipPython函式Filter
- Python 進階之路 (五) map, filter, reduce, zip 一網打盡PythonFilter
- Python map, reduce, filter和sortedPythonFilter
- 更好用的map函式 flatMap函式
- 陣列的 map, filter ,sort和 reduce 用法陣列Filter
- python 學習--map 和 reduce的使用Python
- Spark入門(四)--Spark的map、flatMap、mapToPairSparkAPTAI
- JavaScript 4/30: 陣列的 map, filter 和 reduce 用法JavaScript陣列Filter
- Scala操作Map
- map/reduce實現 排序排序
- [PY3]——對iterator的處理(解析式、map、reduce、filter)Filter
- [譯] 圖解 Map、Reduce 和 Filter 陣列方法圖解Filter陣列
- Hadoop Map Reduce 漫談Hadoop
- Scala 片段2:List的操作符魔法
- [翻譯]map和reduce,處理資料結構的利器資料結構
- 使用 flatMap() 將巢狀的列表合併成一個新的列表巢狀
- 在幕後看看Swift中的Map,Filter和Reduce的實現SwiftFilter
- Python 中的map、reduce函式用法Python函式
- python 中的map,dict,lambda,reduce,filterPythonFilter
- 分散式計算與Map Reduce分散式
- RxJava2原始碼解讀之 Map、FlatMapRxJava原始碼
- Python中的Map、Reduce和Filter函數語言程式設計PythonFilter函數程式設計
- 人人都能學會的python程式設計教程16:map和reducePython程式設計
- Spark運算元:RDD基本轉換操作map、flatMapSpark
- python內建函式 map/reducePython函式
- Map-Reduce資料分析之二
- map、reduce、filter、for...of、for...in等總結Filter
- map/reduce實現資料去重
- JS Array.reduce 實現 Array.map 和 Array.filterJSFilter
- 陣列的reduce操作+物件陣列的map操作陣列物件
- 【Scala篇】--Scala中集合陣列,list,set,map,元祖陣列
- python-python的sao操作 map reduce filterPythonFilter
- Python中map filter reduce的遞迴實現PythonFilter遞迴