深入探討 F# List Module 所提供的 Function (Q ~ Z)
- Version
 - List.reduce
 - List.reduceBack
 - List.replicate
 - List.rev
 - List.scan
 - List.scanBack
 - List.singleton
 - List.skip
 - List.skipWhile
 - List.sort
 - List.sortDescending
 - List.sortBy
 - List.sortByDescending
 - List.sortWith
 - List.splitAt
 - List.splitInto
 - List.sum
 - List.sumBy
 - List.tail
 - List.take
 - List.takeWhild
 - List.toArray
 - List.toSeq
 - List.transpose
 - List.truncate
 - List.tryFind
 - List.tryFindBack
 - List.tryFindIndex
 - List.tryFindIndexBack
 - List.tryHead
 - List.tryItem
 - List.tryLast
 - List.tryPick
 - List.unfold
 - List.unzip
 - List.unzip3
 - List.where
 - List.windowed
 - List.zip
 - List.zip3
 - Conclusion
 - Reference
 
F# 的 List module 提供眾多 List 常用的 Higher Order Function,要能發揮 FP 的威力,首先必須能活用內建 function。
本文探討英文字母 Q ~ Z 開頭的 function。
Version
macOS High Sierra 10.13.3
.NET Core SDK 2.1.101
Rider 2017.3.1
F# 4.1
List.reduce
將 list 中每個 element 的值經過 reduction function 累加
reduction : ('T -> 'T -> 'T) -> list : 'T list -> 'T
1  | [ 1; 2; 3 ]  | 
Q :
List.fold()與List.reduce()有何差異?
1  | [ 1; 2; 3 ]  | 
相同
- 都是 
累加 
相異
List.fold()可以設定初始值;List.reduce()不能設定初始值List.fold()可以不同型別,如(string * int) list-> int;List.reduce()從頭到尾必須相同型別,如int lint -> int
List.reduceBack
將 list 中每個 element 的值從尾部經過 reduction function 累加
reduction : ('T -> 'T -> 'T) -> list : 'T list -> 'T
1  | [ 1; 2; 3 ]  | 
List.replicate
以相同 element 建立 list
count : int -> initial : 'T -> 'T list
1  | List.replicate 3 0  | 
List.rev
將 list 反過來表示
list : 'T list -> 'T list
1  | [ 1; 2; 3 ]  | 
List.scan
類似
List.fold()與List.reduce()對 list 進行累加,但會將計算過程保留在新 list 的 element
folder : ('State -> 'T -> 'State) -> state : 'State -> list : 'T list -> 'State list
1  | [ 1; 2; 3 ]  | 
List.scanBack
同
List.scan(),但從 list 尾部開始累加,並將最後結果先顯示
folder : ('T -> 'State -> 'State) -> list : 'T list -> state : 'State -> 'State list
1  | let list1 = [ 1; 2; 3 ]  | 
List.singleton
將整個 list 成為新 list 的第一個 element
value : 'T -> 'T list
1  | [ 1; 2; 3 ]  | 
List.skip
忽略前 n 個 element 並傳回新 list
count : int -> list : 'T list -> 'T list
1  | [ 1 .. 10 ]  | 
List.skipWhile
忽略前 n 個符合 predicate function 的 element,若第一個 element 不符合則停止 skip
predicate : ('T -> bool) -> list : 'T list -> 'T list
1  | [ 1 .. 10 ]  | 
List.sort
將 list 排序 (由小到大)
list : 'T list -> 'T list
1  | [ 3; 2; 1 ]  | 
List.sortDescending
將 list 排序 (由大到小)
list : 'T list -> 'T list
1  | [ 1; 2; 3 ]  | 
List.sortBy
將 list 的 element 透過 projection function 轉換過,再根據 key 排序 (由小到大)
projection : ('T -> 'Key) -> list : 'T list -> 'T list
1  | [ 3; 2; 1 ]  | 
List.sortByDescending
將 list 的 element 透過 projection function 轉換過,再根據 key 排序 (由大到小)
projection : ('T -> 'Key) -> list : 'T list -> 'T list
1  | [ 1; 2; 3 ]  | 
List.sortWith
將 list 的 element 透過 comparer function 排序
comparer : ('T -> 'T -> int) -> list : 'T list -> 'T list
1  | [ 3; 2; 1 ]  | 
List.splitAt
將 list 根據指定 index 分成兩個 list
index : int -> list : 'T list -> 'T list * 'T list
1  | [ 1 .. 10 ]  | 
List.splitInto
將 list 分成指定 chunk 數
count : int -> list : 'T list -> 'T list list
1  | [ 1 .. 10 ]  | 
List.sum
將 list 中所有 element 相加
list : 'T list -> 'T
1  | [ 1; 2; 3 ]  | 
List.sumBy
將 list 先將過 projection function 運算後再相加,相當於
List.map()+List.sum()
projection : ('T -> 'U) -> list : 'T list -> 'U
1  | [ 1; 2; 3 ]  | 
相當於
1  | [ 1; 2; 3 ]  | 
List.tail
將 list 除了第 1 個 element 外,剩下的 list 傳回,相當於 list 的
Tailproperty
list : 'T list -> 'T list
1  | [ 1; 2; 3 ]  | 
List.take
回傳 list 前 n 個 element
count : int -> list : 'T list -> 'T list
1  | [ 1 .. 10 ]  | 
Q :
List.truncate()與List.take()有何差異?
當 n 大於 Length 時,List.truncate() 不會報錯,只是將整個 list 傳回;但 List.take() 拋出 InvalidOperationException
List.takeWhild
回傳前 n 個符合 predicate function 的 element,若第一個 element 不符合則停止 take
predicate : ('T -> bool) -> list : 'T list -> 'T list
1  | [ 1 .. 10 ]  | 
List.toArray
將 list 轉成 array
list : 'T list -> 'T []
1  | [ 1; 2; 3 ]  | 
List.toSeq
將 list 轉成 sequence
list : 'T list -> seq<'T>
1  | [ 1; 2; 3 ]  | 
List.transpose
將 sequence 內的 list 加以 transpose
list : seq<'T list> -> 'T list list
1  | [[ 1; 2; 3]]  | 
List.truncate
回傳 list 最多 n 的 element
count : int -> list : 'T list -> 'T list
1  | [1; 2; 3]  | 
Q :
List.truncate()與List.take()有何差異?
當 n 大於 Length 時,List.truncate() 不會報錯,只是將整個 list 傳回;但 List.take() 拋出 InvalidOperationException
List.tryFind
找出 list 中符合 predicate function 條件的第一個 element
predicate : ('T -> bool) -> list : 'T list -> 'T option
1  | [ 1 .. 10 ]  | 
List.find()與List.tryFind()有何差異?
相同
- 都使用 predicate function 為搜尋條件
 
相異
List.find()傳回'T;而List.tryFind()傳回'T option若找不到資料,
List.find()會拋出KeyNotFoundException;但List.tryFind()只會回傳None
實務上建議使用
List.tryFind()取代List.find(),較為安全
List.tryFindBack
從 list 尾部找出符合 predicate function 條件的第一個 element
predicate:('T -> bool) -> list : 'T list -> 'T option
1  | [ 1 .. 10 ]  | 
Q:
List.findBack()與List.tryFindBack()有何差異?
相同
- 都使用 predicate function 為搜尋條件
 
相異
List.findBack()傳回'T;而List.tryFindBack()傳回'T option若找不到資料,
List.findBack()會拋出KeyNotFoundException;但List.tryFindBack()只會回傳None
實務上建議使用
List.tryFindBack()取代List.findBack(),較為安全
List.tryFindIndex
找出 list 中符合 predicate function 條件的第一 element 的 index
predicate : ('T -> bool) -> list : 'T list -> int option
1  | [ 1 .. 10 ]  | 
Q:
List.findIndex()與List.tryFindIndex()有何差異?
相同
- 都使用 predicate function 為搜尋條件
 
相異
List.findIndex()傳回int;而List.tryFindIndex()傳回int option若找不到資料,
List.findIndex()會拋出KeyNotFoundException;但List.tryFindIndex()只會回傳None
實務上建議使用
List.tryFindIndex()取代List.findIndex(),較為安全
List.tryFindIndexBack
從 list 尾部找出符合 predicate function 條件的第一 element 的 index
predicate : ('T -> bool) -> list : 'T list -> int option
1  | [ 1 .. 10 ]  | 
Q:
List.findIndexBack()與List.tryFindIndexBack()有何差異?
相同
- 都使用 predicate function 為搜尋條件
 
相異
List.findIndexBack()傳回int;而List.tryFindIndexBack()傳回int option若找不到資料,
List.findIndexBack()會拋出KeyNotFoundException;但List.tryFindIndexBack()只會回傳None
實務上建議使用
List.tryFindIndexBack()取代List.findIndexBack(),較為安全
List.tryHead
傳回 list 第一個 element,相當於 list 的
Headproperty
list : 'T list -> 'T option
1  | [ 1; 2; 3 ]  | 
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.tryItem
傳回 list 指定 index 的 element 值,相當於 list 的
Itemproperty
index : int -> list : 'T list -> 'T option
1  | [ 1; 2; 3 ]  | 
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.tryLast
傳回 list 最後一個 element
list : 'T list -> 'T option
1  | [ 1; 2; 3 ]  | 
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.tryPick
找出 list 中符合 chooser function 條件的第一個 element
chooser : ('T -> 'U option) -> list : 'T list -> 'U option
1  | let chooser elm =  | 
Q:
List.pick()與List.tryPick()有何差異?
相同
- 都使用 chooser function 為搜尋條件
 
相異
List.pick()傳回'U;而List.tryPick()傳回'U option若找不到資料,
List.pick()會拋出KeyNotFoundException;但List.tryPick()只會回傳None
實務上建議使用
List.tryPick()取代List.pick(),較為安全
List.unfold
根據 generator function 建立 list,其中 generator function 可指定目前 state 與下一個 state
generator : ('State -> ('T * 'State) option) -> state : 'State -> 'T list
1  | let generator state =  | 
List.unzip
將所有 element 為 pair 的 list,分解成兩個 list
list : ('T1 * 'T2) list -> 'T1 list * 'T2 list
1  | [ (1, 4); (2, 5); (3, 6) ]  | 
List.unzip3
將所有 element 為 triple 的 list,分解成三個 list
list : ('T1 * 'T2 * 'T3) list -> 'T1 list * 'T2 list * 'T3 list
1  | [ (1, 4, 7); (2, 5, 8); (3, 6, 9) ]  | 
List.where
找出 list 中符合 predicate function 條件的所有 element
predicate : ('T -> bool) -> list : 'T list -> 'T list
1  | [ 1; 2; 3]  | 
List.windowed
依照 list 的 element 順序,依序取出 n 個 element 的 list
windowSize : int -> list : 'T list -> 'T list list
1  | [ 1 .. 5 ]  | 
List.zip
將兩個 list 合併成 element 為 pair 的 list
list1 : 'T1 list -> list2 : 'T2 list -> ('T1 * 'T2) list
1  | let list1 = [ 1; 2; 3 ]  | 
List.zip3
將三個 list 合併成 element 為 triple 的 list
list1 : 'T1 list -> list2 : 'T2 list -> list3 : 'T3 list -> ('T1 * 'T2 * 'T3) list
1  | let list1 = [ 1; 2; 3 ]  | 
Conclusion
- List module 所提供的 function 都必須非常熟練,因為這些都是常用的 Higher Order Function,算是 FP 的基本功