- F# 基礎教程
- F# - 首頁
- F# - 概覽
- F# - 環境設定
- F# - 程式結構
- F# - 基本語法
- F# - 資料型別
- F# - 變數
- F# - 運算子
- F# - 決策
- F# - 迴圈
- F# - 函式
- F# - 字串
- F# - 可選值
- F# - 元組
- F# - 記錄
- F# - 列表
- F# - 序列
- F# - 集合
- F# - 對映
- F# - 辨析聯合
- F# - 可變資料
- F# - 陣列
- F# - 可變列表
- F# - 可變字典
- F# - 基本 I/O
- F# - 泛型
- F# - 委託
- F# - 列舉
- F# - 模式匹配
- F# - 異常處理
- F# - 類
- F# - 結構體
- F# - 運算子過載
- F# - 繼承
- F# - 介面
- F# - 事件
- F# - 模組
- F# - 名稱空間
F# - 列表
在 F# 中,列表是一個有序的、不可變的相同型別元素序列。在某種程度上,它等價於連結串列資料結構。
F# 模組 Microsoft.FSharp.Collections.List 包含了列表的常用操作。但是,F# 自動匯入此模組並使其可用於每個 F# 應用程式。
建立和初始化列表
以下是建立列表的各種方法:
使用列表**字面量**。
使用**cons** (::) 運算子。
使用 List 模組的**List.init** 方法。
使用一些稱為**列表推導式**的**語法結構**。
列表字面量
在這種方法中,您只需在方括號中指定一個用分號分隔的值序列。例如:
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
cons (::) 運算子
使用此方法,您可以透過使用 :: 運算子將某些值新增到現有列表的開頭或**cons** 到現有列表中。例如:
let list2 = 1::2::3::4::5::6::7::8::9::10::[];;
[] 表示空列表。
List init 方法
List 模組的 List.init 方法通常用於建立列表。此方法具有以下型別:
val init : int -> (int -> 'T) -> 'T list
第一個引數是新列表所需的長度,第二個引數是初始化函式,用於生成列表中的項。
例如,
let list5 = List.init 5 (fun index -> (index, index * index, index * index * index))
在這裡,索引函式生成列表。
列表推導式
列表推導式是用於生成列表的特殊語法結構。
F# 列表推導式語法有兩種形式:範圍和生成器。
範圍具有以下結構:[start .. end] 和 [start .. step .. end]
例如,
let list3 = [1 .. 10]
生成器具有以下結構:[for x in collection do ... yield expr]
例如,
let list6 = [ for a in 1 .. 10 do yield (a * a) ]
由於**yield** 關鍵字將單個值推送到列表中,因此**yield!** 關鍵字將值的集合推送到列表中。
以下函式演示了上述方法:
示例
(* using list literals *) let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] printfn "The list: %A" list1 (*using cons operator *) let list2 = 1 :: 2 :: 3 :: [] printfn "The list: %A" list2 (* using range constructs*) let list3 = [1 .. 10] printfn "The list: %A" list3 (* using range constructs *) let list4 = ['a' .. 'm'] printfn "The list: %A" list4 (* using init method *) let list5 = List.init 5 (fun index -> (index, index * index, index * index * index)) printfn "The list: %A" list5 (* using yield operator *) let list6 = [ for a in 1 .. 10 do yield (a * a) ] printfn "The list: %A" list6 (* using yield operator *) let list7 = [ for a in 1 .. 100 do if a % 3 = 0 && a % 5 = 0 then yield a] printfn "The list: %A" list7 (* using yield! operator *) let list8 = [for a in 1 .. 3 do yield! [ a .. a + 3 ] ] printfn "The list: %A" list8
編譯並執行程式時,它將生成以下輸出:
The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] The list: [1; 2; 3] The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] The list: ['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'i'; 'j'; 'k'; 'l'; 'm'] The list: [(0, 0, 0); (1, 1, 1); (2, 4, 8); (3, 9, 27); (4, 16, 64)] The list: [1; 4; 9; 16; 25; 36; 49; 64; 81; 100] The list: [15; 30; 45; 60; 75; 90] The list: [1; 2; 3; 4; 2; 3; 4; 5; 3; 4; 5; 6]
列表資料型別的屬性
下表顯示了列表資料型別的各種屬性:
| 屬性 | 型別 | 描述 |
|---|---|---|
| Head | 'T | 第一個元素。 |
| Empty | 'T list | 一個靜態屬性,返回適當型別的空列表。 |
| IsEmpty | bool | 如果列表沒有元素,則為**true**。 |
| Item | 'T | 指定索引處的元素(從零開始)。 |
| Length | int | 元素的數量。 |
| Tail | 'T list | 沒有第一個元素的列表。 |
以下示例顯示了這些屬性的使用:
示例
let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ] // Use of Properties printfn "list1.IsEmpty is %b" (list1.IsEmpty) printfn "list1.Length is %d" (list1.Length) printfn "list1.Head is %d" (list1.Head) printfn "list1.Tail.Head is %d" (list1.Tail.Head) printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head) printfn "list1.Item(1) is %d" (list1.Item(1))
編譯並執行程式時,它將生成以下輸出:
list1.IsEmpty is false list1.Length is 8 list1.Head is 2 list1.Tail.Head is 4 list1.Tail.Tail.Head is 6 list1.Item(1) is 4
列表的基本運算子
下表顯示了列表資料型別上的基本操作:
| 值 | 描述 |
|---|---|
| append : 'T list → 'T list → 'T list | 返回一個新列表,其中包含第一個列表的元素,後跟第二個列表的元素。 |
| average : 'T list → ^T | 返回列表中元素的平均值。 |
| averageBy : ('T → ^U) → 'T list → ^U | 返回透過將函式應用於列表的每個元素生成的元素的平均值。 |
| choose : ('T → 'U option) → 'T list → 'U list | 將給定函式應用於列表的每個元素。返回由函式返回**Some** 的每個元素的結果組成的列表。 |
| collect : ('T → 'U list) → 'T list → 'U list | 對於列表的每個元素,應用給定函式。連線所有結果並返回組合列表。 |
| concat : seq<'T list> → 'T list | 返回一個新列表,其中包含每個列表的元素(按順序)。 |
| empty : 'T list | 返回給定型別的空列表。 |
| exists : ('T → bool) → 'T list → bool | 測試列表中的任何元素是否滿足給定的謂詞。 |
| exists2 : ('T1 → 'T2 → bool) → 'T1 list → 'T2 list → bool | 測試列表的任何一對對應元素是否滿足給定的謂詞。 |
| filter : ('T → bool) → 'T list → 'T list | 返回一個新集合,其中僅包含給定謂詞返回**true** 的集合的元素。 |
| find : ('T → bool) → 'T list → 'T | 返回給定函式返回**true** 的第一個元素。 |
| findIndex : ('T → bool) → 'T list → int | 返回列表中第一個滿足給定謂詞的元素的索引。 |
| fold : ('State → 'T → 'State) → 'State → 'T list → 'State | 將函式應用於集合的每個元素,將累加器引數貫穿計算。此函式獲取第二個引數,並將其與列表的第一個元素一起應用於函式。然後,它將此結果與第二個元素一起傳遞給函式,依此類推。最後,它返回最終結果。如果輸入函式為 f,元素為 i0...iN,則此函式計算 f (... (f s i0) i1 ...) iN。 |
| fold2 : ('State → 'T1 → 'T2 → 'State) → 'State → 'T1 list → 'T2 list → 'State | 將函式應用於兩個集合的對應元素,將累加器引數貫穿計算。集合的大小必須相同。如果輸入函式為 f,元素為 i0...iN 和 j0...jN,則此函式計算 f (... (f s i0 j0)...) iN jN。 |
| foldBack : ('T → 'State → 'State) → 'T list → 'State → 'State | 將函式應用於集合的每個元素,將累加器引數貫穿計算。如果輸入函式為 f,元素為 i0...iN,則計算 f i0 (...(f iN s))。 |
| foldBack2 : ('T1 → 'T2 → 'State → 'State) → 'T1 list → 'T2 list → 'State → 'State | 將函式應用於兩個集合的對應元素,將累加器引數貫穿計算。集合的大小必須相同。如果輸入函式為 f,元素為 i0...iN 和 j0...jN,則此函式計算 f i0 j0 (...(f iN jN s))。 |
| forall : ('T → bool) → 'T list → bool | 測試集合的所有元素是否滿足給定的謂詞。 |
| forall2 : ('T1 → 'T2 → bool) → 'T1 list → 'T2 list → bool | 測試集合的所有對應元素是否成對滿足給定的謂詞。 |
| head : 'T list → 'T | 返回列表的第一個元素。 |
| init : int → (int → 'T) → 'T list | 透過在每個索引上呼叫給定的生成器來建立列表。 |
| isEmpty : 'T list → bool | 如果列表不包含任何元素,則返回**true**,否則返回**false**。 |
| iter : ('T → unit) → 'T list → unit | 將給定函式應用於集合的每個元素。 |
| iter2 : ('T1 → 'T2 → unit) → 'T1 list → 'T2 list → unit | 同時將給定函式應用於兩個集合。集合的大小必須相同。 |
| iteri : (int → 'T → unit) → 'T list → unit | 將給定函式應用於集合的每個元素。傳遞給函式的整數表示元素的索引。 |
| iteri2 : (int → 'T1 → 'T2 → unit) → 'T1 list → 'T2 list → unit | 同時將給定函式應用於兩個集合。集合的大小必須相同。傳遞給函式的整數表示元素的索引。 |
| length : 'T list → int | 返回列表的長度。 |
| map : ('T → 'U) → 'T list → 'U list | 建立一個新集合,其元素是將給定函式應用於集合的每個元素的結果。 |
| map2 : ('T1 → 'T2 → 'U) → 'T1 list → 'T2 list → 'U list | 建立一個新集合,其元素是將給定函式應用於兩個集合的對應元素的結果(成對)。 |
| map3 : ('T1 → 'T2 → 'T3 → 'U) → 'T1 list → 'T2 list → 'T3 list → 'U list | 建立一個新集合,其元素是將給定函式同時應用於三個集合的對應元素的結果。 |
| mapi : (int → 'T → 'U) → 'T list → 'U list | 建立一個新集合,其元素是將給定函式應用於集合的每個元素的結果。傳遞給函式的整數索引表示正在轉換的元素的索引(從 0 開始)。 |
| mapi2 : (int → 'T1 → 'T2 → 'U) → 'T1 list → 'T2 list → 'U list | 類似於 List.mapi,但對映兩個等長列表的對應元素。 |
| max : 'T list → 'T | 返回列表中所有元素中最大的元素,透過使用 Operators.max 進行比較。 |
| maxBy : ('T → 'U) → 'T list → 'T | 返回列表中所有元素中最大的元素,透過使用 Operators.max 對函式結果進行比較。 |
| min : 'T list → 'T | 返回列表中所有元素中最小的元素,透過使用 Operators.min 進行比較。 |
| minBy : ('T → 'U) → 'T list → 'T | 返回列表中所有元素中最小的元素,使用 Operators.min 對函式結果進行比較。 |
| nth : 'T list → int → 'T | 索引到列表中。第一個元素的索引為 0。 |
| ofArray : 'T [] → 'T list | 根據給定的陣列建立列表。 |
| ofSeq : seq<'T> → 'T list | 根據給定的可列舉物件建立一個新的列表。 |
| partition : ('T → bool) → 'T list * 'T list | 將集合拆分為兩個集合,分別包含給定謂詞返回 **true** 和 **false** 的元素。 |
| permute : (int → int) → 'T list → 'T list | 返回一個列表,其中所有元素都根據指定的排列進行排列。 |
| pick : ('T → 'U option) → 'T list → 'U | 將給定函式應用於連續的元素,返回函式對於某個值返回 **Some** 的第一個結果。 |
| reduce : ('T → 'T → 'T) → 'T list → 'T | 將一個函式應用於集合的每個元素,將一個累加器引數貫穿計算過程。此函式將指定的函式應用於列表的前兩個元素。然後,它將此結果與第三個元素一起傳遞給函式,依此類推。最後,它返回最終結果。如果輸入函式為 f,元素為 i0...iN,則此函式計算 f (... (f i0 i1) i2 ...) iN。 |
| reduceBack : ('T → 'T → 'T) → 'T list → 'T | 將一個函式應用於集合的每個元素,將一個累加器引數貫穿計算過程。如果輸入函式為 f,元素為 i0...iN,則此函式計算 f i0 (...(f iN-1 iN))。 |
| replicate : (int → 'T → 'T list) | 透過在每個索引上呼叫給定的生成器來建立列表。 |
| rev : 'T list → 'T list | 返回一個新的列表,其中元素的順序相反。 |
| scan : ('State → 'T → 'State) → 'State → 'T list → 'State list | 將一個函式應用於集合的每個元素,將一個累加器引數貫穿計算過程。此函式獲取第二個引數,並將指定的函式應用於它和列表的第一個元素。然後,它將此結果與第二個元素一起傳遞給函式,依此類推。最後,它返回中間結果和最終結果的列表。 |
| scanBack : ('T → 'State → 'State) → 'T list → 'State → 'State list | 類似於 foldBack,但返回中間結果和最終結果。 |
| sort : 'T list → 'T list | 使用 Operators.compare 對給定列表進行排序。 |
| sortBy : ('T → 'Key) → 'T list → 'T list | 使用給定投影給出的鍵對給定列表進行排序。使用 Operators.compare 比較鍵。 |
| sortWith : ('T → 'T → int) → 'T list → 'T list | 使用給定的比較函式對給定列表進行排序。 |
| sum : ^T list → ^T | 返回列表中元素的總和。 |
| sumBy : ('T → ^U) → 'T list → ^U | 返回將函式應用於列表的每個元素生成的的結果的總和。 |
| tail : 'T list → 'T list | 返回輸入列表,但不包括第一個元素。 |
| toArray : 'T list → 'T [] | 根據給定的列表建立一個數組。 |
| toSeq : 'T list → seq<'T> | 將給定列表視為一個序列。 |
| tryFind : ('T → bool) → 'T list → 'T option | 返回給定函式返回 **true** 的第一個元素。如果不存在這樣的元素,則返回 **None**。 |
| tryFindIndex : ('T → bool) → 'T list → int option | 返回列表中第一個滿足給定謂詞的元素的索引。如果不存在這樣的元素,則返回 **None**。 |
| tryPick : ('T → 'U option) → 'T list → 'U option | 將給定函式應用於連續的元素,返回函式對於某個值返回 **Some** 的第一個結果。如果不存在這樣的元素,則返回 **None**。 |
| unzip : ('T1 * 'T2) list → 'T1 list * 'T2 list | 將一個配對列表拆分為兩個列表。 |
| unzip3 : ('T1 * 'T2 * 'T3) list → 'T1 list * 'T2 list * 'T3 list | 將一個三元組列表拆分為三個列表。 |
| zip : 'T1 list → 'T2 list → ('T1 * 'T2) list | 將兩個列表組合成一個配對列表。兩個列表必須具有相同的長度。 |
| zip3 : 'T1 list → 'T2 list → 'T3 list → ('T1 * 'T2 * 'T3) list | 將三個列表組合成一個三元組列表。列表必須具有相同的長度。 |
以下示例演示了上述功能的使用。
示例 1
此程式顯示了遞迴反轉列表。
let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]
printfn "The original list: %A" list1
let reverse lt =
let rec loop acc = function
| [] -> acc
| hd :: tl -> loop (hd :: acc) tl
loop [] lt
printfn "The reversed list: %A" (reverse list1)
編譯並執行程式時,它將生成以下輸出:
The original list: [2; 4; 6; 8; 10; 12; 14; 16] The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]
但是,您可以使用模組的 **rev** 函式來實現相同目的。
let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ] printfn "The original list: %A" list1 printfn "The reversed list: %A" (List.rev list1)
編譯並執行程式時,它將生成以下輸出:
The original list: [2; 4; 6; 8; 10; 12; 14; 16] The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]
示例 2
此程式顯示了使用 **List.filter** 方法過濾列表。
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] printfn "The list: %A" list1 let list2 = list1 |> List.filter (fun x -> x % 2 = 0);; printfn "The Filtered list: %A" list2
編譯並執行程式時,它將生成以下輸出:
The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] The Filtered list: [2; 4; 6; 8; 10]
示例 3
**List.map** 方法將一個列表從一種型別對映到另一種型別。
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] printfn "The list: %A" list1 let list2 = list1 |> List.map (fun x -> (x * x).ToString());; printfn "The Mapped list: %A" list2
編譯並執行程式時,它將生成以下輸出:
The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] The Mapped list: ["1"; "4"; "9"; "16"; "25"; "36"; "49"; "64"; "81"; "100"]
示例 4
**List.append** 方法和 @ 運算子將一個列表附加到另一個列表。
let list1 = [1; 2; 3; 4; 5 ] let list2 = [6; 7; 8; 9; 10] let list3 = List.append list1 list2 printfn "The first list: %A" list1 printfn "The second list: %A" list2 printfn "The appened list: %A" list3 let lt1 = ['a'; 'b';'c' ] let lt2 = ['e'; 'f';'g' ] let lt3 = lt1 @ lt2 printfn "The first list: %A" lt1 printfn "The second list: %A" lt2 printfn "The appened list: %A" lt3
編譯並執行程式時,它將生成以下輸出:
The first list: [1; 2; 3; 4; 5] The second list: [6; 7; 8; 9; 10] The appened list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] The first list: ['a'; 'b'; 'c'] The second list: ['e'; 'f'; 'g'] The appened list: ['a'; 'b'; 'c'; 'e'; 'f'; 'g']
示例 5
**List.sort** 方法對列表進行排序。**List.sum** 方法給出列表中元素的總和,而 **List.average** 方法給出列表中元素的平均值。
let list1 = [9.0; 0.0; 2.0; -4.5; 11.2; 8.0; -10.0] printfn "The list: %A" list1 let list2 = List.sort list1 printfn "The sorted list: %A" list2 let s = List.sum list1 let avg = List.average list1 printfn "The sum: %f" s printfn "The average: %f" avg
編譯並執行程式時,它將生成以下輸出:
The list: [9.0; 0.0; 2.0; -4.5; 11.2; 8.0; -10.0] The sorted list: [-10.0; -4.5; 0.0; 2.0; 8.0; 9.0; 11.2] The sum: 15.700000 The average: 2.242857
“摺疊”操作將一個函式應用於列表中的每個元素,將函式的結果聚合到一個累加器變數中,並將累加器作為摺疊操作的結果返回。
示例 6
**List.fold** 方法從左到右將函式應用於每個元素,而 **List.foldBack** 方法從右到左將函式應用於每個元素。
let sumList list = List.fold (fun acc elem -> acc + elem) 0 list printfn "Sum of the elements of list %A is %d." [ 1 .. 10 ] (sumList [ 1 .. 10 ])
編譯並執行程式時,它將生成以下輸出:
Sum of the elements of list [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] is 55.