Lists
在F#中,列表是有序的,不可变的相同类型的元素系列。 它在某种程度上等同于链表数据结构。
F#模块Microsoft.FSharp.Collections.List,对列表具有常见操作。 但是,F#会自动导入此模块,并使每个F#应用程序都可以访问它。
创建和初始化列表
以下是创建列表的各种方法 -
使用列表literals 。
使用cons (::)运算符。
使用List模块的List.init方法。
使用一些名为List Comprehensions syntactic constructs 。
列出文字
在此方法中,您只需在方括号中指定以分号分隔的值序列。 例如 -
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The cons (::) Operator
使用此方法,您可以使用::运算符通过在现有列表中添加或使用它来添加一些值。 例如 -
let list2 = 1::2::3::4::5::6::7::8::9::10::[];;
[]表示一个空列表。
列出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#list comprehension语法有两种形式 - 范围和生成器。
范围有结构 - [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!,将一组值推送到列表中。
以下函数演示了上述方法 -
例子 (Example)
(* 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 | 没有第一个元素的列表。 |
以下示例显示了这些属性的用法 -
例子 (Example)
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
列表中的基本运算符
下表显示了列表数据类型的基本操作 -
值 | 描述 |
---|---|
追加:'T列表→'T列表→'T列表 | 返回一个新列表,其中包含第一个列表的元素,后跟第二个列表的元素。 |
平均值:'T list→^ T. | 返回列表中元素的平均值。 |
averageBy:('T→^ U)→'T list→^ U. | 返回通过将函数应用于列表的每个元素而生成的元素的平均值。 |
选择:('T→'U选项)→'T列表→'U列表 | 将给定函数应用于列表的每个元素。 返回由函数返回Some每个元素的结果组成的列表。 |
收集:('T→'U列表)→'T列表→'U列表 | 对于列表的每个元素,应用给定的函数。 连接所有结果并返回组合列表。 |
concat:seq →'T列表 | 返回一个新列表,按顺序包含每个列表的元素。 |
empty : 'T list | 返回给定类型的空列表。 |
存在:('T→bool)→'T list→bool | 测试列表中的任何元素是否满足给定谓词。 |
exists2:('T1→'T2→bool)→'T1 list→'T2 list→bool | 测试列表的任何一对相应元素是否满足给定谓词。 |
filter:('T→bool)→'T list→'T列表 | 返回一个新集合,该集合仅包含给定谓词返回true的集合元素。 |
找到:('T→bool)→'T list→'T | 返回给定函数返回true的第一个元素。 |
findIndex:('T→bool)→'T list→int | 返回列表中满足给定谓词的第一个元素的索引。 |
fold:('State→'T→'State)→'State→'T list→'State | 将函数应用于集合的每个元素,通过计算线程化累加器参数。 此函数接受第二个参数,并将函数应用于它和列表的第一个元素。 然后,它将此结果与第二个元素一起传递给函数,依此类推。 最后,它返回最终结果。 如果输入函数是f并且元素是i0 ... iN,则此函数计算f(...(fs i0)i1 ...)iN。 |
fold2 :('状态→'T1→'T2→'状态)→'状态→'T1列表→'T2列表→'状态 | 将函数应用于两个集合的相应元素,通过计算线程化累加器参数。 集合必须具有相同的大小。 如果输入函数是f并且元素是i0 ... iN和j0 ... jN,则此函数计算f(...(fs i0 j0)...)iN jN。 |
foldBack :('T→'州→'州)→'T列表→'州→'州 | 将函数应用于集合的每个元素,通过计算线程化累加器参数。 如果输入函数是f并且元素是i0 ... iN,则计算f i0(...(f iN s))。 |
foldBack2 :('T1→'T2→'状态→'状态)→'T1列表→'T2列表→'状态→'状态 | 将函数应用于两个集合的相应元素,通过计算线程化累加器参数。 集合必须具有相同的大小。 如果输入函数是f并且元素是i0 ... iN和j0 ... jN,则该函数计算f i0 j0(...(f iN jN s))。 |
forall:('T→bool)→'T list→bool | 测试集合的所有元素是否满足给定的谓词。 |
forall2:('T1→'T2→bool)→'T1列表→'T2列表→布尔 | 测试集合的所有相应元素是否成对满足给定谓词。 |
head:'T list→'T | 返回列表的第一个元素。 |
init:int→(int→'T)→'T列表 | 通过在每个索引上调用给定的生成器来创建列表。 |
isEmpty:'T list→bool | 如果列表不包含元素,则返回true ,否则返回false 。 |
iter:('T→unit)→'T list→unit | 将给定函数应用于集合的每个元素。 |
iter2:('T1→'T2→单位)→'T1列表→'T2列表→单位 | 将给定函数同时应用于两个集合。 集合必须具有相同的大小。 |
iteri:(int→'T→unit)→'T list→unit | 将给定函数应用于集合的每个元素。 传递给函数的整数表示元素的索引。 |
iteri2:(int→'T1→'T2→单位)→'T1列表→'T2列表→单位 | 将给定函数同时应用于两个集合。 集合必须具有相同的大小。 传递给函数的整数表示元素的索引。 |
length:'T list→int | 返回列表的长度。 |
map:('T→'U)→'T list→'U列表 | 创建一个新集合,其元素是将给定函数应用于集合的每个元素的结果。 |
map2:('T1→'T2→'U)→'T1列表→'T2列表→'U列表 | 创建一个新集合,其元素是将给定函数成对应用于两个集合的相应元素的结果。 |
map3:('T1→'T2→'T3→'U)→'T1列表→'T2列表→'T3列表→'U列表 | 创建一个新集合,其元素是将给定函数同时应用于三个集合的相应元素的结果。 |
mapi:(int→'T→'U)→'T list→'U列表 | 创建一个新集合,其元素是将给定函数应用于集合的每个元素的结果。 传递给函数的整数索引表示正在转换的元素的索引(从0开始)。 |
mapi2:(int→'T1→'T2→'U)→'T1列表→'T2列表→'U列表 | 与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列表 | 从给定数组创建列表。 |
ofSeq:seq →'T列表 | 从给定的可枚举对象创建新列表。 |
分区:('T→bool)→'T list *'T列表 | 将集合拆分为两个集合,其中包含给定谓词分别返回true和false的元素。 |
permute:(int→int)→'T list→'T列表 | 返回一个列表,其中所有元素都根据指定的排列进行置换。 |
选择:('T→'U选项)→'T列表→'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))。 |
复制:(int→'T→'T列表) | 通过在每个索引上调用给定的生成器来创建列表。 |
rev:'T list→'T列表 | 返回包含相反顺序元素的新列表。 |
扫描:('状态→'T→'状态)→'状态→'T列表→'状态列表 | 将函数应用于集合的每个元素,通过计算线程化累加器参数。 此函数接受第二个参数,并将指定的函数应用于它和列表的第一个元素。 然后,它将此结果与第二个元素一起传递给函数,依此类推。 最后,它返回中间结果列表和最终结果。 |
scanBack :('T→'State→'State)→'T list→'State→'状态列表 | 像foldBack一样,但返回中间和最终结果 |
sort:'T list→'T列表 | 使用Operators.compare对给定列表进行排序。 |
sortBy:('T→'Key)→'T list→'T列表 | 使用给定投影给出的键对给定列表进行排序。 使用Operators.compare比较密钥。 |
sortWith:('T→'T→int)→'T list→'T列表 | 使用给定的比较函数对给定列表进行排序。 |
sum:^ T list→^ T. | 返回列表中元素的总和。 |
sumBy:('T→^ U)→'T list→^ U. | 返回通过将函数应用于列表的每个元素而生成的结果的总和。 |
tail:'T list→'T列表 | 返回没有第一个元素的输入列表。 |
toArray:'T list→'T [] | 从给定列表创建一个数组。 |
toSeq:'T list→seq | 将给定列表视为序列。 |
tryFind:('T→bool)→'T list→'T选项 | 返回给定函数返回true的第一个元素。 如果不存在此类元素,则返回None 。 |
tryFindIndex :('T→bool)→'T list→int选项 | 返回列表中满足给定谓词的第一个元素的索引。 如果不存在此类元素,则返回None 。 |
tryPick :('T→'U选项)→'T列表→'U选项 | 将给定函数应用于连续元素,返回第一个结果,其中函数返回Some值。 如果不存在此类元素,则返回None 。 |
解压:('T1 *'T2)列表→'T1列表*'T2列表 | 将对列表拆分为两个列表。 |
unzip3:('T1 *'T2 *'T3)列表→'T1列表*'T2列表*'T3列表 | 将三元组列表拆分为三个列表。 |
zip:'T1 list→'T2 list→('T1 *'T2)列表 | 将两个列表组合成一对列表。 这两个列表必须具有相同的长度。 |
zip3:'T1列表→'T2列表→'T3列表→('T1 *'T2 *'T3)列表 | 将三个列表组合成三元组列表。 列表必须具有相同的长度。 |
以下示例演示了上述功能的用途 -
例子1 (Example 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 (Example 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 (Example 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 (Example 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 (Example 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.