深入探討 F# List Module 所提供的 Function (G ~ P)
- Version
- List.head
- List.indexed
- List.init
- List.isEmpty
- List.item
- List.iter
- List.iter2
- List.iteri
- List.iteri2
- List.last
- List.length
- List.map
- List.map2
- List.map3
- List.mapFold
- List.mapFoldBack
- List.mapi
- List.mapi2
- List.max
- List.maxBy
- List.min
- List.minBy
- List.ofArray
- List.ofSeq
- List.pairWise
- List.partition
- List.permute
- List.pick
- Conclusion
- Reference
F# 的 List module 提供眾多 List
常用的 Higher Order Function,要能發揮 FP 的威力,首先必須能活用內建 function。
本文探討英文字母 G ~ P 開頭的 function。
Version
macOS High Sierra 10.13.3
.NET Core SDK 2.1.101
Rider 2017.3.1
F# 4.1
List.head
傳回 list 第一個 element,相當於 list 的
Head
property
list : 'T list -> 'T
1 | [ 1; 2; 3 ] |
若為 empty list,會拋出 ArgumentException
。
Q:
List.head()
與List.tryHead()
有何差異?
相同
- 都傳回 list 第一個 element
相異
List.head()
傳回'T
;而List.tryHead()
傳回'T option
若找不到資料,
List.head()
會拋出ArgumentException
;但List.tryHead()
只會回傳None
實務上建議使用
List.tryHead()
取代List.head()
,較為安全
List.indexed
將 element 的 key 與 value 封裝成 tuple 的 list
list : 'T list -> (int * 'T) list
1 | [ 1; 2; 3 ] |
List.init
根據 index 值建立新的 list
int -> initializer : (int -> 'T) -> 'T list
1 | List.init 10 (fun idx -> idx * 2) |
List.isEmpty
判斷 list 是否為空,相當於 list 的
IsEmpty
property
list : 'T list -> bool
1 | [] |
List.item
傳回 list 指定 index 的 element 值,相當於 list 的
Item
property
index : int -> list : 'T list -> 'T
1 | [ 1; 2; 3 ] |
若找不到 element,會拋出 ArgumentException
。
Q:
List.item()
與List.tryItem()
有何差異?
相同
- 都傳回 list 指定 index 的 element 值
相異
List.item()
傳回'T
;而List.tryItem()
傳回'T option
若找不到資料,
List.head()
會拋出ArgumentException
;但List.tryHead()
只會回傳None
實務上建議使用
List.tryItem()
取代List.item()
,較為安全
List.iter
對每個 element 執行回傳值為
unit
的 action function
action : ('T -> unit) -> list : 'T list -> unit
1 | [ 1; 2; 3 ] |
List.iter2
同時對兩個 list 的每個 element 執行回傳值為
unit
的 action function
action : ('T1 -> 'T2 -> unit) -> list1 : 'T1 list -> list2 : 'T2 list -> unit
1 | let list1 = [ 1; 2; 3 ] |
List.iteri
對每個 element 執行回傳值為
unit
的 action function,但會將 index 也傳入 action function
action : (int -> 'T -> unit) -> list : 'T list -> unit
1 | [ 1 .. 3 ] |
List.iteri2
同時對兩個 list 的每個 element 執行回傳值為
unit
的 action function,但會將 index 也傳入 action function
action : (int -> 'T1 -> 'T2 -> unit) -> list1 : 'T1 list -> list2 : 'T2 list -> unit
1 | let list1 = [ 1; 2; 3 ] |
List.last
傳回 list 最後一個 element
list : 'T list -> 'T
1 | [ 1; 2; 3 ] |
若找不到 element,會拋出 ArgumentException
。
Q:
List.last()
與List.tryLast()
有何差異?
相同
- 都傳回 list 最後一個 element 值
相異
List.last()
傳回'T
;而List.tryLast()
傳回'T option
若找不到資料,
List.last()
會拋出ArgumentException
;但List.tryLast()
只會回傳None
實務上建議使用
List.tryLast()
取代List.last()
,較為安全
List.length
傳回 list 的 element 個數,相當於 list 的
Length
property
list: 'T list -> int
1 | [ 1; 2; 3 ] |
List.map
將 list 的每個 element 根據 mapping function 轉換成另外一個 value 的 list
mapping : ('T -> 'U) -> list : 'T list -> 'U list
1 | [ 1; 2; 3 ] |
若經過 mapping function 後 element 個數不一樣,請用 List.collect()
List.map2
將兩個 list 的每個 element 根據 mapping function 轉換成另外一個 value 的 list
mapping : ('T1 -> 'T2 -> 'U) -> list1 : 'T1 list -> list2 : 'T2 list -> 'U list
1 | let list1 = [ 1; 2; 3 ] |
List.map3
將三個 list 的每個 element 根據 mapping function 轉換成另外一個 value 的 list
mapping : ('T1 -> 'T2 -> 'T3 -> 'U) -> list1 : 'T1 list -> list2 : 'T2 list -> list3 : 'T3 list -> 'U list
1 | let list1 = [ 1; 2; 3 ] |
List.mapFold
相當於
List.map()
+List.fold()
合體,回傳為 tuple。
mapping : ('State -> 'T -> 'Result * 'State) -> state : 'State -> list : 'T list -> 'Result list * 'State
1 | [ 1; 2; 3 ] |
mapping funciton 中,回傳的是 tuple。
- 第 1 個 element 為
List.map()
的結果 - 第 2 個 element 為
List.fold()
的結果
List.mapFoldBack
相當於
List.map()
+List.fold()
合體,回傳為 tuple,但從 list 的尾部開始,signature 的順序也不一樣
mapping : ('T -> 'State -> 'Result * 'State) -> list : 'T list -> state : 'State -> 'Result * 'State
1 | let list1 = [ 1; 2; 3 ] |
List.mapi
對 list 的每個 element 根據 mapping function 轉換成另外一個 value 的 list,但會將 index 也傳入 mapping function
mapping : (int -> 'T -> 'U) -> list : 'T list -> 'U list
1 | [ 1; 2; 3 ] |
List.mapi2
同時對兩個 list 的每個 element 根據 mapping function 轉換成另外一個 value 的 list,但會將 index 也傳入 mapping function
1 | let list1 = [ 1; 2; 3 ] |
List.max
傳回 list 內 element 最大值
list : 'T list -> 'T
1 | [ 1; 2; 3 ] |
List.maxBy
傳回 list 內 element 最大值,但所比較的是經過 projection function 轉換過的值
project : ('T -> 'U) -> list : 'T list -> 'T
1 | [ 1; 2; 3 ] |
[1; 2; 3]
經過 projection function 後為 [0; -1; -2]
,所以最大值為 0
,但 List.maxBy()
回傳的是原 list 的值,所以為 1
。
Projection function 的值只是比較用,不是回傳用
List.min
傳回 list 內 element 最小值
list : 'T list -> 'T
1 | [ 1; 2; 3 ] |
List.minBy
傳回 list 內 element 最小值,但所比較的是經過 projection function 轉換過的值
project : ('T -> 'U) -> list : 'T list -> 'T
1 | [ 1; 2; 3 ] |
[1; 2; 3]
經過 projection function 後為 [0; -1; -2]
,所以最小值為 0
,但 List.minBy()
回傳的是原 list 的值,所以為 3
。
Projection function 的值只是比較用,不是回傳用
List.ofArray
由 array 轉成 list
array : 'T [] -> 'T list
1 | [| 1; 2; 3 |] |
List.ofSeq
由 sequence 轉成 list
source : seq<'T> -> 'T list
1 | seq { 1 .. 5 } |
List.pairWise
根據 list 順序,回傳兩兩成為 tuple 的 list
list : 'T list -> ('T * 'T) list
1 | [ 1; 2; 3; 4 ] |
List.partition
將 list 根據 predicate function 條件拆成兩個 list
predicate : ('T -> bool) -> list : 'T list -> 'T list * 'T list
1 | [ 1 .. 10 ] |
List.permute
List 重新根據 indexMap function 的規則,重新調整 element 順序
indexMap : (int -> int) -> list : 'T list -> 'T list
1 | [ 1; 2; 3 ] |
List.pick
找出 list 中符合 chooser function 條件的第一個 element
chooser : ('T -> 'U option) -> list : 'T list -> -> 'U
1 | let chooser elm = |
若找不到 element,會拋出 KeyNotFoundException
。
Q:
List.find()
與List.pick()
有何差異?
相同
都用來找資料
找不到資料都會拋出
KeyNotFoundException
相異
List.find()
的 predicate function 為'T -> bool
List.pick()
的 chooser function 為'T -> 'U option
若 fuction 回傳為
option
,則適合用List.pick()
,否則使用List.find()
Conclusion
- List module 所提供的 function 都必須非常熟練,因為這些都是常用的 Higher Order Function,算是 FP 的基本功