F# - 数组



数组是固定大小、从零开始、可变的连续数据元素集合,这些元素都属于相同的类型。

创建数组

您可以使用各种语法和方法或使用 Array 模块中的函数来创建数组。在本节中,我们将讨论在不使用模块函数的情况下创建数组。

在不使用函数的情况下,有三种创建数组的语法方法:

  • 列出 [| 和 |] 之间的连续值,并用分号分隔。
  • 将每个元素放在单独一行,在这种情况下,分号分隔符是可选的。
  • 使用序列表达式。

您可以使用点运算符 (.) 和方括号 ([ 和 ]) 访问数组元素。

以下示例演示了如何创建数组:

//using semicolon separator
let array1 = [| 1; 2; 3; 4; 5; 6 |]
for i in 0 .. array1.Length - 1 do
   printf "%d " array1.[i]
printfn" "

// without semicolon separator
let array2 =
   [|
      1
      2
      3
      4
      5
   |]
for i in 0 .. array2.Length - 1 do
   printf "%d " array2.[i]
printfn" "

//using sequence
let array3 = [| for i in 1 .. 10 -> i * i |]
for i in 0 .. array3.Length - 1 do
   printf "%d " array3.[i]
printfn" "

编译并执行程序时,将生成以下输出:

1 2 3 4 5 6
1 2 3 4 5
1 4 9 16 25 36 49 64 81 100

数组的基本操作

库模块 Microsoft.FSharp.Collections.Array 支持对一维数组的操作。

下表显示了数组的基本操作:

描述
append : 'T [] → 'T [] → 'T [] 创建一个包含一个数组的元素后跟另一个数组的元素的数组。
average : ^T [] → ^T 返回数组中元素的平均值。
averageBy : ('T → ^U) → 'T [] → ^U 返回将函数应用于数组的每个元素生成的元素的平均值。
blit : 'T [] → int → 'T [] → int → int → unit 读取一个数组中的一系列元素并将它们写入另一个数组。
choose : ('T → U option) → 'T [] → 'U [] 将提供的函数应用于数组的每个元素。返回一个数组,其中包含每个元素的结果 x,对于这些元素,函数返回 Some(x)。
collect : ('T → 'U []) → T [] → 'U [] 将提供的函数应用于数组的每个元素,连接结果,并返回组合的数组。
concat : seq<'T []> → 'T [] 创建一个包含提供的数组序列的每个元素的元素的数组。
copy : 'T → 'T [] 创建一个包含提供的数组的元素的数组。
create : int → 'T → 'T [] 创建一个数组,其元素最初都是提供的值。
empty : 'T [] 返回给定类型的空数组。
exists : ('T → bool) → 'T [] → bool 测试数组的任何元素是否满足提供的谓词。
exists2 : ('T1 → 'T2 → bool) → 'T1 [] → 'T2 [] → bool 测试两个数组的任何一对对应元素是否满足提供的条件。
fill : 'T [] → int → int → 'T → unit 用提供的值为数组的一系列元素填充。
filter : ('T → bool) → 'T [] → 'T [] 返回一个集合,其中仅包含提供的数组中提供的条件返回 true 的元素。
find : ('T → bool) → 'T [] → 'T 返回提供的函数返回 true 的第一个元素。如果不存在这样的元素,则引发 KeyNotFoundException。
findIndex : ('T → bool) → 'T [] → int 返回数组中第一个满足提供的条件的元素的索引。如果元素都不满足该条件,则引发 KeyNotFoundException。
fold : ('State → 'T → 'State) → 'State → 'T [] → 'State 将函数应用于数组的每个元素,将累加器参数贯穿计算。如果输入函数是 f 并且数组元素是 i0...iN,则此函数计算 f (...(f s i0)...) iN。
fold2 : ('State → 'T1 → 'T2 → 'State) → 'State → 'T1 [] → 'T2 [] → 'State 将函数应用于两个提供的数组中元素对,从左到右,将累加器参数贯穿计算。两个输入数组必须具有相同的长度;否则,将引发 ArgumentException。
foldBack : ('T → 'State → 'State) → 'T [] → 'State → 'State 将函数应用于数组的每个元素,将累加器参数贯穿计算。如果输入函数是 f 并且数组元素是 i0...iN,则此函数计算 f i0 (...(f iN s))。
foldBack2 : ('T1 → 'T2 → 'State → 'State) → 'T1 [] → 'T2 [] → 'State → 'State 将函数应用于两个提供的数组中元素对,从右到左,将累加器参数贯穿计算。两个输入数组必须具有相同的长度;否则,将引发 ArgumentException。
forall : ('T → bool) → 'T [] → bool 测试数组的所有元素是否满足提供的条件。
forall2 : ('T1 → 'T2 → bool) → 'T1 [] → 'T2 [] → bool 测试两个提供的数组的所有对应元素是否满足提供的条件。
get : 'T [] → int → 'T 从数组中获取元素。
init : int → (int → 'T) → 'T [] 使用提供的函数创建指定维度的数组。
isEmpty : 'T [] → bool 测试数组是否有任何元素。
iter : ('T → unit) → 'T [] → unit 将提供的函数应用于数组的每个元素。
iter2 : ('T1 → 'T2 → unit) → 'T1 [] → 'T2 [] → unit) 将提供的函数应用于两个数组中匹配索引的一对元素。两个数组必须具有相同的长度;否则,将引发 ArgumentException。
iteri : (int → 'T → unit) → 'T [] → unit 将提供的函数应用于数组的每个元素。传递给函数的整数指示元素的索引。
iteri2 : (int → 'T1 → 'T2 → unit) → 'T1 [] → 'T2 [] → unit 将提供的函数应用于两个数组中匹配索引的一对元素,还传递元素的索引。两个数组必须具有相同的长度;否则,将引发 ArgumentException。
length : 'T [] → int 返回数组的长度。Length 属性执行相同操作。
map : ('T → 'U) → 'T [] → 'U [] 创建一个数组,其元素是将提供的函数应用于提供的数组的每个元素的结果。
map2 : ('T1 → 'T2 → 'U) → 'T1 [] → 'T2 [] → 'U [] 创建一个数组,其元素是将提供的函数应用于两个提供的数组的对应元素的结果。两个输入数组必须具有相同的长度;否则,将引发 ArgumentException。
mapi : (int → 'T → 'U) → 'T [] → 'U [] 创建一个数组,其元素是将提供的函数应用于提供的数组的每个元素的结果。传递给函数的整数索引指示正在转换的元素的索引。
mapi2 : (int → 'T1 → 'T2 → 'U) → 'T1 [] → 'T2 [] → 'U [] 创建一个数组,其元素是将提供的函数应用于两个集合的对应元素成对的结果,还传递元素的索引。两个输入数组必须具有相同的长度;否则,将引发 ArgumentException。
max : 'T [] → 'T 返回数组所有元素中最大的一个。Operators.max 用于比较元素。
maxBy : ('T → 'U) → 'T [] → 'T 返回数组所有元素中最大的一个,通过函数结果上的 Operators.max 进行比较。
min : ('T [] → 'T 返回数组所有元素中最小的一个。Operators.min 用于比较元素。
minBy : ('T → 'U) → 'T [] → 'T 返回数组所有元素中最小的一个。Operators.min 用于比较元素。
ofList : 'T list → 'T [] 从提供的列表创建数组。
ofSeq : seq<'T> → 'T [] 从提供的可枚举对象创建数组。
partition : ('T → bool) → 'T [] → 'T [] * 'T [] 将数组拆分为两个数组,一个包含提供的条件返回 true 的元素,另一个包含返回 false 的元素。
permute : (int → int) → 'T [] → 'T [] 根据指定的排列对数组的元素进行排列。
pick : ('T → 'U option) → 'T [] → 'U 将提供的函数应用于提供的数组的连续元素,返回函数为某个 x 返回 Some(x) 的第一个结果。如果函数从未返回 Some(x),则引发 KeyNotFoundException。
reduce : ('T → 'T → 'T) → 'T [] → 'T 将函数应用于数组的每个元素,将累加器参数贯穿计算。如果输入函数是 f 并且数组元素是 i0...iN,则此函数计算 f (...(f i0 i1)...) iN。如果数组大小为零,则引发 ArgumentException。
reduceBack : ('T → 'T → 'T) → 'T [] → 'T

将函数应用于数组的每个元素,并将累加器参数贯穿计算过程。如果输入函数为 f,元素为 i0...iN,则此函数计算 f i0 (...(f iN-1 iN))。如果数组大小为零,则引发 ArgumentException。
rev : 'T [] → 'T [] 反转提供的数组中元素的顺序。
scan : ('State → 'T → 'State) → 'State → 'T [] → 'State []) 行为类似于 fold,但会将中间结果与最终结果一起返回。
scanBack : ('T → 'State → 'State) → 'T [] → 'State → 'State [] 行为类似于 foldBack,但会将中间结果与最终结果一起返回。
set : 'T [] → int → 'T → unit 设置数组中的一个元素。
sort : 'T[] → 'T [] 对数组中的元素进行排序并返回一个新数组。使用 Operators.compare 来比较元素。
sortBy : ('T → 'Key) → 'T [] → 'T [] 使用提供的函数将元素转换为排序操作所基于的类型,对数组中的元素进行排序,并返回一个新数组。使用 Operators.compare 来比较元素。
sortInPlace : 'T [] → unit 通过就地更改数组来对数组中的元素进行排序,使用提供的比较函数。使用 Operators.compare 来比较元素。
sortInPlaceBy : ('T → 'Key) → 'T [] → unit 通过就地更改数组来对数组中的元素进行排序,使用提供的键投影。使用 Operators.compare 来比较元素。
sortInPlaceWith : ('T → 'T → int) → 'T [] → unit 使用提供的比较函数对数组中的元素进行排序,并就地更改数组。
sortWith : ('T → 'T → int) → 'T [] → 'T [] 使用提供的比较函数对数组中的元素进行排序,并返回一个新数组。
sub : 'T [] → int → int → 'T [] 创建一个包含提供的子范围的数组,该子范围由起始索引和长度指定。
sum : 'T [] → ^T 返回数组中元素的总和。
sumBy : ('T → ^U) → 'T [] → ^U 返回将函数应用于数组的每个元素后生成的每个结果的总和。
toList : 'T [] → 'T list 将提供的数组转换为列表。
toSeq : 'T [] → seq<'T> 将提供的数组视为一个序列。
tryFind : ('T → bool) → 'T [] → 'T option 返回提供的数组中第一个使提供的函数返回 true 的元素。如果不存在这样的元素,则返回 None
tryFindIndex : ('T → bool) → 'T [] → int option 返回数组中第一个满足提供的条件的元素的索引。
tryPick : ('T → 'U option) → 'T [] → 'U option 将提供的函数应用于提供的数组的连续元素,并返回函数返回 Some(x)(对于某个 x)的第一个结果。如果函数从未返回 Some(x),则返回 None
unzip : ('T1 * 'T2) [] → 'T1 [] * 'T2 [] 将元组对数组拆分为两个数组的元组。
unzip3 : ('T1 * 'T2 * 'T3) [] → 'T1 [] * 'T2 [] * 'T3 [] 将三个元素的元组数组拆分为三个数组的元组。
zeroCreate : int → 'T [] 创建一个数组,其元素最初设置为默认值 Unchecked.defaultof<'T>。
zip : 'T1 [] → 'T2 [] → ('T1 * 'T2) [] 将两个数组组合成一个有两个元素的元组数组。这两个数组必须具有相同的长度;否则,将引发 ArgumentException。
zip3 : 'T1 [] → 'T2 [] → 'T3 [] → ('T1 * 'T2 * 113 'T3) [] 将三个数组组合成一个有三个元素的元组数组。这三个数组必须具有相同的长度;否则,将引发 ArgumentException。

在下一节中,我们将看到其中一些功能的用法。

使用函数创建数组

Array 模块提供了一些从头开始创建数组的函数。

  • Array.empty 函数创建一个新的空数组。

  • Array.create 函数创建一个指定大小的数组,并将所有元素设置为给定值。

  • Array.init 函数创建一个数组,给定一个维度和一个生成元素的函数。

  • Array.zeroCreate 函数创建一个数组,其中所有元素都初始化为零值。

  • Array.copy 函数创建一个新数组,其中包含从现有数组复制的元素。

  • Array.sub 函数从数组的子范围生成一个新数组。

  • Array.append 函数通过组合两个现有数组来创建一个新数组。

  • Array.choose 函数选择数组的元素以包含在新数组中。

  • Array.collect 函数对现有数组的每个数组元素运行指定的函数,然后收集函数生成的元素并将它们组合到一个新数组中。

  • Array.concat 函数获取一系列数组并将它们组合成一个数组。

  • Array.filter 函数获取一个布尔条件函数,并生成一个新数组,其中只包含输入数组中条件为真的那些元素。

  • Array.rev 函数通过反转现有数组的顺序来生成一个新数组。

以下示例演示了这些函数 -

示例 1

(* using create and set *)
let array1 = Array.create 10 ""
for i in 0 .. array1.Length - 1 do
   Array.set array1 i (i.ToString())
for i in 0 .. array1.Length - 1 do
   printf "%s " (Array.get array1 i)
printfn " "

(* empty array *)
let array2 = Array.empty
printfn "Length of empty array: %d" array2.Length

let array3 = Array.create 10 7.0
printfn "Float Array: %A" array3

(* using the init and zeroCreate *)
let array4 = Array.init 10 (fun index -> index * index)
printfn "Array of squares: %A" array4

let array5 : float array = Array.zeroCreate 10
let (myZeroArray : float array) = Array.zeroCreate 10
printfn "Float Array: %A" array5

编译并执行程序时,将生成以下输出:

0 1 2 3 4 5 6 7 8 9
Length of empty array: 0
Float Array: [|7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0|]
Array of squares: [|0; 1; 4; 9; 16; 25; 36; 49; 64; 81|]
Float Array: [|0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0|]

示例 2

(* creating subarray from element 5 *)
(* containing 15 elements thereon *)

let array1 = [| 0 .. 50 |]
let array2 = Array.sub array1 5 15
printfn "Sub Array:"
printfn "%A" array2

(* appending two arrays *)
let array3 = [| 1; 2; 3; 4|]
let array4 = [| 5 .. 9 |]
printfn "Appended Array:"
let array5 = Array.append array3 array4
printfn "%A" array5

(* using the Choose function *)
let array6 = [| 1 .. 20 |]
let array7 = Array.choose (fun elem -> if elem % 3 = 0 then
   Some(float (elem))
      else
   None) array6

printfn "Array with Chosen elements:"
printfn "%A" array7

(*using the Collect function *)
let array8 = [| 2 .. 5 |]
let array9 = Array.collect (fun elem -> [| 0 .. elem - 1 |]) array8
printfn "Array with collected elements:"
printfn "%A" array9

编译并执行程序时,将生成以下输出:

Sub Array:
[|5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19|]
Appended Array:
[|1; 2; 3; 4; 5; 6; 7; 8; 9|]
Array with Chosen elements:
[|3.0; 6.0; 9.0; 12.0; 15.0; 18.0|]
Array with collected elements:
[|0; 1; 0; 1; 2; 0; 1; 2; 3; 0; 1; 2; 3; 4|]

搜索数组

Array.find 函数获取一个布尔函数,并返回第一个使函数返回 true 的元素,否则引发 KeyNotFoundException。

Array.findIndex 函数的工作方式类似,只是它返回元素的索引而不是元素本身。

以下示例演示了这一点。

Microsoft 提供了这个有趣的程序示例,它查找给定数字范围内第一个既是完全平方数又是完全立方数的元素 -

let array1 = [| 2 .. 100 |]
let delta = 1.0e-10
let isPerfectSquare (x:int) =
   let y = sqrt (float x)
   abs(y - round y) < delta

let isPerfectCube (x:int) =
   let y = System.Math.Pow(float x, 1.0/3.0)
   abs(y - round y) < delta

let element = Array.find (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1

let index = Array.findIndex (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1

printfn "The first element that is both a square and a cube is %d and its index is %d." element index

编译并执行程序时,将生成以下输出:

The first element that is both a square and a cube is 64 and its index is 62.
广告

© . All rights reserved.