深入探討 F# List Module 所提供的 Function (Q ~ Z)

栏目: ASP.NET · 发布时间: 6年前

内容简介:F# 的 List module 提供眾多本文先探討英文字母 Q ~ Z 開頭的 function。macOS High Sierra 10.13.3

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

JetBrains Rider 2017.3.1

F# 4.1

List.reduce

將 list 中每個 element 的值經過 reduction function 累加

reduction : ('T -> 'T -> 'T) -> list : 'T list -> 'T

[ 1; 2; 3 ]
|> List.reduce (fun acc elm -> acc + elm)
|> printf "%A"
// 6

Q : List.fold()List.reduce() 有何差異?

[ 1; 2; 3 ]
|> List.fold (fun elm acc -> acc + elm) 0
|> printf "%A"
// 6

相同

  • 都是 累加

相異

  • 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; 2; 3 ]
|> List.reduceBack (fun elm acc -> acc + elm)
|> printf "%A"
// 6

List.replicate

以相同 element 建立 list

count : int -> initial : 'T -> 'T list

List.replicate 3 0
|> printf "%A"
// [0; 0; 0]

List.rev

將 list 反過來表示

list : 'T list -> 'T list

[ 1; 2; 3 ]
|> List.rev
|> printf "%A"
// [3; 2; 1]

List.scan

類似 List.fold()List.reduce() 對 list 進行累加,但會將計算過程保留在新 list 的 element

folder : ('State -> 'T -> 'State) -> state : 'State -> list : 'T list -> 'State list

[ 1; 2; 3 ]
|> List.scan (fun acc elm -> acc + elm) 0
|> printf "%A"
// [0; 1; 3; 6]

List.scanBack

List.scan() ,但從 list 尾部開始累加,並將最後結果先顯示

folder : ('T -> 'State -> 'State) -> list : 'T list -> state : 'State -> 'State list

let list1 = [ 1; 2; 3 ]

List.scanBack (fun elm acc -> acc + elm) list1 0
|> printf "%A"
// [6; 5; 3; 0]

List.singleton

將整個 list 成為新 list 的第一個 element

value : 'T -> 'T list

[ 1; 2; 3 ]
|>List.singleton
|> printf "%A"
// [[1; 2; 3]]

List.skip

忽略前 n 個 element 並傳回新 list

count : int -> list : 'T list -> 'T list

[ 1 .. 10 ]
|>List.skip 5
|> printf "%A"
// [6; 7; 8; 9; 10]

List.skipWhile

忽略前 n 個符合 predicate function 的 element,若第一個 element 不符合則停止 skip

predicate : ('T -> bool) -> list : 'T list -> 'T list

[ 1 .. 10 ]
|>List.skipWhile (fun elm -> elm < 5)
|> printf "%A"
// [5; 6; 7; 8; 9; 10]

List.sort

將 list 排序 (由小到大)

list : 'T list -> 'T list

[ 3; 2; 1 ]
|>List.sort
|> printf "%A"
// [1; 2; 3]

List.sortDescending

將 list 排序 (由大到小)

list : 'T list -> 'T list

[ 1; 2; 3 ]
|>List.sortDescending
|> printf "%A"
// [3; 2; 1]

List.sortBy

將 list 的 element 透過 projection function 轉換過,再根據 key 排序 (由小到大)

projection : ('T -> 'Key) -> list : 'T list -> 'T list

[ 3; 2; 1 ]
|>List.sortBy (fun elm -> elm)
|> printf "%A"
// [1; 2; 3]

List.sortByDescending

將 list 的 element 透過 projection function 轉換過,再根據 key 排序 (由大到小)

projection : ('T -> 'Key) -> list : 'T list -> 'T list

[ 1; 2; 3 ]
|>List.sortByDescending (fun elm -> elm)
|> printf "%A"
// [3; 2; 1]

List.sortWith

將 list 的 element 透過 comparer function 排序

comparer : ('T -> 'T -> int) -> list : 'T list -> 'T list

[ 3; 2; 1 ]
|>List.sortWith (fun elm1 elm2 -> elm1 - elm2)
|> printf "%A"
// [1; 2; 3]

List.splitAt

將 list 根據指定 index 分成兩個 list

index : int -> list : 'T list -> 'T list * 'T list

[ 1 .. 10 ]
|>List.splitAt 5
|> printf "%A"
// ([1; 2; 3; 4; 5], [6; 7; 8; 9; 10])

List.splitInto

將 list 分成指定 chunk 數

count : int -> list : 'T list -> 'T list list

[ 1 .. 10 ]
|>List.splitInto 3 
|> printf "%A"
// [[1; 2; 3; 4]; [5; 6; 7]; [8; 9; 10]]

List.sum

將 list 中所有 element 相加

list : 'T list -> 'T

[ 1; 2; 3 ]
|>List.sum
|> printf "%A"
// 6

List.sumBy

將 list 先將過 projection function 運算後再相加,相當於 List.map() + List.sum()

projection : ('T -> 'U) -> list : 'T list -> 'U

[ 1; 2; 3 ]
|>List.sumBy (fun elm -> elm * elm)
|> printf "%A"
// 14

相當於

[ 1; 2; 3 ]
|> List.map (fun elm -> elm * elm)
|> List.sum
|> printf "%A"
// 14

List.tail

將 list 除了第 1 個 element 外,剩下的 list 傳回,相當於 list 的 Tail property

list : 'T list -> 'T list

[ 1; 2; 3 ]
|>List.tail
|> printf "%A"
// [2; 3]

List.take

回傳 list 前 n 個 element

count : int -> list : 'T list -> 'T list

[ 1 .. 10 ]
|>List.take 3
|> printf "%A"
// [1; 2; 3]

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 .. 10 ]
|>List.takeWhile (fun elm -> elm < 5)
|> printf "%A"
// [1; 2; 3; 4]

List.toArray

將 list 轉成 array

list : 'T list -> 'T []

[ 1; 2; 3 ]
|>List.toArray
|> printf "%A"
// [|1; 2; 3|]

List.toSeq

將 list 轉成 sequence

list : 'T list -> seq<'T>

[ 1; 2; 3 ]
|>List.toSeq
|> printf "%A"
// [1; 2; 3]

List.transpose

將 sequence 內的 list 加以 transpose

list : seq<'T list> -> 'T list list

[[ 1; 2; 3]]
|>List.transpose
|> printf "%A"
// [[1]; [2]; [3]]

List.truncate

回傳 list 最多 n 的 element

count : int -> list : 'T list -> 'T list

[1; 2; 3]
|>List.truncate 6
|> printf "%A"
// [1; 2]

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 .. 10 ]
|> List.tryFind (fun elm -> elm % 2 = 0)
|> printf "%A"
// Some 2

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 .. 10 ]
|> List.tryFindBack (fun elm -> elm % 2 = 0)
|> printf "%A"
// Some 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 .. 10 ]
|> List.tryFindIndex (fun elm -> elm % 2 = 0)
|> printf "%A"
// Some 1

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 .. 10 ]
|> List.tryFindIndexBack (fun elm -> elm % 2 = 0)
|> printf "%A"
// Some 9

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 的 Head property

list : 'T list -> 'T option

[ 1; 2; 3 ]
|> List.tryHead
|> printf "%A"
// Some 1

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 的 Item property

index : int -> list : 'T list -> 'T option

[ 1; 2; 3 ]
|> List.tryItem 2
|> printf "%A"
// Some 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; 2; 3 ]
|> List.tryLast
|> printf "%A"
// Some 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

let chooser elm = 
    match elm with 
    | elm when elm % 2 = 0 -> Some elm
    | _ -> None

[ 1; 2; 3 ]
|> List.tryPick chooser
|> printf "%A"
// Some 2

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

let generator state =
    match state with 
    |_ when state < 10 -> Some(state, state + 1)
    |_                 -> None

List.unfold generator 0
|> printf "%A"
// [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]

List.unzip

將所有 element 為 pair 的 list,分解成兩個 list

list : ('T1 * 'T2) list -> 'T1 list * 'T2 list

[ (1, 4); (2, 5); (3, 6) ]
|> List.unzip
|> printf "%A"
// ([1; 2; 3], [4; 5; 6])

List.unzip3

將所有 element 為 triple 的 list,分解成三個 list

list : ('T1 * 'T2 * 'T3) list -> 'T1 list * 'T2 list * 'T3 list

[ (1, 4, 7); (2, 5, 8); (3, 6, 9) ]
|> List.unzip3
|> printf "%A"
// ([1; 2; 3], [4; 5; 6], [7; 8; 9])

List.where

找出 list 中符合 predicate function 條件的所有 element

predicate : ('T -> bool) -> list : 'T list -> 'T list

[ 1; 2; 3]
|> List.where (fun elm -> elm % 2 = 1)
|> printf "%A"
// [1; 3]

List.windowed

依照 list 的 element 順序,依序取出 n 個 element 的 list

windowSize : int -> list : 'T list -> 'T list list

[ 1 .. 5 ]
|> List.windowed 3
|> printf "%A"
// [[1; 2; 3]; [2; 3; 4]; [3; 4; 5]]

List.zip

將兩個 list 合併成 element 為 pair 的 list

list1 : 'T1 list -> list2 : 'T2 list -> ('T1 * 'T2) list

let list1 = [ 1; 2; 3 ]
let list2 = [ 4; 5; 6 ]

List.zip list1 list2
|> printf "%A"
// [(1, 4); (2, 5); (3, 6)]

List.zip3

將三個 list 合併成 element 為 triple 的 list

list1 : 'T1 list -> list2 : 'T2 list -> list3 : 'T3 list -> ('T1 * 'T2 * 'T3) list

let list1 = [ 1; 2; 3 ]
let list2 = [ 4; 5; 6 ]
let list3 = [ 7; 8; 9 ]

List.zip3 list1 list2 list3
|> printf "%A"
// [(1, 4, 7); (2, 5, 8); (3, 6, 9)]

Conclusion

  • List module 所提供的 function 都必須非常熟練,因為這些都是常用的 Higher Order Function,算是 FP 的基本功

Reference

MSDN , Collection.List Module (F#)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

敏捷软件开发

敏捷软件开发

马丁 / 邓辉、孙鸣 / 人民邮电出版社 / 2008-01-01 / 69.00元

《敏捷软件开发:原则模式和实践(C#版)》不仅是一部深入浅出、生动易懂的面向对象原则与设计模式著作。而且还是一部通俗的敏捷方法导引书和快速实用的LJML教程。通过《敏捷软件开发:原则模式和实践(C#版)》你会发现,许多以前看起来非常枯燥费解的概念,忽然间都豁然开朗。变得鲜活生动起来。 C#版与此前的Java版相比,主要的更新包括加强了UML的介绍章节。使其更加贴近实战;增加了对MVP模式的介......一起来看看 《敏捷软件开发》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具