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.
广告
© . All rights reserved.