列表Lists

F# 中的列表是一个有序的、不可变的同类型元素系列。A list in F# is an ordered, immutable series of elements of the same type. 若要对列表执行基本操作,请使用 列表模块中的函数。To perform basic operations on lists, use the functions in the List module.

创建和初始化列表Creating and Initializing Lists

可以通过以下方式来定义列表:显式列出元素并用分号分隔各个元素,然后将这些元素用方括号括起来,如下面的代码行所示。You can define a list by explicitly listing out the elements, separated by semicolons and enclosed in square brackets, as shown in the following line of code.

let list123 = [ 1; 2; 3 ]

也可以在各个元素之间插入换行符,在这种情况下,分号是可选的。You can also put line breaks between elements, in which case the semicolons are optional. 当元素初始化表达式较长或你希望为每个元素包含一个注释时,后一种语法会产生可读性更高的代码。The latter syntax can result in more readable code when the element initialization expressions are longer, or when you want to include a comment for each element.

let list123 = [
    1
    2
    3 ]

通常,所有列表元素都必须是同一类型。Normally, all list elements must be the same type. 但存在一种例外情况,即其元素被指定为基类型的列表中包含的元素可以是派生类型。An exception is that a list in which the elements are specified to be a base type can have elements that are derived types. 由于 ButtonCheckBox 都派生自 Control,因此以下内容是可接受的。Thus the following is acceptable, because both Button and CheckBox derive from Control.

let myControlList : Control list = [ new Button(); new CheckBox() ]

也可以使用由范围分隔符 (..) 分隔的整数所指示的范围来定义列表元素,如以下代码所示。You can also define list elements by using a range indicated by integers separated by the range operator (..), as shown in the following code.

let list1 = [ 1 .. 10 ]

可使用一对中间不包含任何内容的方括号来指定空列表。An empty list is specified by a pair of square brackets with nothing in between them.

// An empty list.
let listEmpty = []

也可以使用序列表达式来创建列表。You can also use a sequence expression to create a list. 有关详细信息,请参阅 序列表达式See Sequence Expressions for more information. 例如,以下代码创建一个从 1 到 10 的整数的平方值的列表。For example, the following code creates a list of squares of integers from 1 to 10.

let listOfSquares = [ for i in 1 .. 10 -> i*i ]

用于处理列表的运算符Operators for Working with Lists

可以使用 :: (cons) 运算符将元素附加到列表中。You can attach elements to a list by using the :: (cons) operator. 如果 list1[2; 3; 4],则以下代码会将 list2 创建为 [100; 2; 3; 4]If list1 is [2; 3; 4], the following code creates list2 as [100; 2; 3; 4].

let list2 = 100 :: list1

可以使用 @ 运算符来串联具有可兼容类型的列表,如以下代码所示。You can concatenate lists that have compatible types by using the @ operator, as in the following code. 如果 list1[2; 3; 4],且 list2[100; 2; 3; 4],则此代码会将 list3 创建为 [2; 3; 4; 100; 2; 3; 4]If list1 is [2; 3; 4] and list2 is [100; 2; 3; 4], this code creates list3 as [2; 3; 4; 100; 2; 3; 4].

let list3 = list1 @ list2

列表模块中提供了用于对列表执行操作的函数。Functions for performing operations on lists are available in the List module.

由于 F# 中的列表是不可变的,因此任何修改操作都会生成新列表,而不是修改现有列表。Because lists in F# are immutable, any modifying operations generate new lists instead of modifying existing lists.

F # 中的列表实现为单独链接列表,这意味着仅访问列表头的操作是 O (1) ,元素访问是 O (n) 。Lists in F# are implemented as singly linked lists, which means that operations that access only the head of the list are O(1), and element access is O(n).

属性Properties

列表类型支持以下属性:The list type supports the following properties:

propertiesProperty 类型Type 说明Description
Head 'T 第一个元素。The first element.
EmptyEmpty 'T list 返回适合类型的空列表的静态属性。A static property that returns an empty list of the appropriate type.
IsEmptyIsEmpty bool 如果列表不包含任何元素,则为 truetrue if the list has no elements.
ItemItem 'T 位于指定索引处(从零开始)的元素。The element at the specified index (zero-based).
长度Length int 元素数量。The number of elements.
TailTail 'T list 不带第一个元素的列表。The list without the first element.

以下是一些使用这些属性的示例。Following are some examples of using these properties.

let list1 = [ 1; 2; 3 ]

// 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))

使用列表Using Lists

利用列表进行编程,你可以使用少量代码来执行复杂的操作。Programming with lists enables you to perform complex operations with a small amount of code. 本节介绍针对列表的常见操作,这些操作对于函数编程很重要。This section describes common operations on lists that are important to functional programming.

利用列表进行递归Recursion with Lists

列表特别适合于递归编程技术。Lists are uniquely suited to recursive programming techniques. 假设要对列表的每个元素执行某个操作。Consider an operation that must be performed on every element of a list. 可以通过以下方式来实现递归:对列表头执行操作,然后再次将列表尾(一个更小的列表,它由不带第一个元素的原始列表组成)传递回下一级递归。You can do this recursively by operating on the head of the list and then passing the tail of the list, which is a smaller list that consists of the original list without the first element, back again to the next level of recursion.

若要编写此类递归函数,可在模式匹配中使用 cons 运算符 (::),以便将列表头与列表尾分离。To write such a recursive function, you use the cons operator (::) in pattern matching, which enables you to separate the head of a list from the tail.

以下代码示例显示了如何使用模式匹配来实现对列表执行操作的递归函数。The following code example shows how to use pattern matching to implement a recursive function that performs operations on a list.

let rec sum list =
   match list with
   | head :: tail -> head + sum tail
   | [] -> 0

上面的代码非常适用于小型列表,但对于大型列表,它可能会溢出堆栈。The previous code works well for small lists, but for larger lists, it could overflow the stack. 以下代码通过使用累加器自变量(一种用于处理递归函数的标准技术)对该代码进行了改进。The following code improves on this code by using an accumulator argument, a standard technique for working with recursive functions. 使用累加器参数会使函数进行尾递归,这将节省堆栈空间。The use of the accumulator argument makes the function tail recursive, which saves stack space.

let sum list =
   let rec loop list acc =
       match list with
       | head :: tail -> loop tail (acc + head)
       | [] -> acc
   loop list 0

函数 RemoveAllMultiples 是一个递归函数,它采用两个列表。The function RemoveAllMultiples is a recursive function that takes two lists. 第一个列表包含一些数字(将移除这些数字的倍数),第二个列表是要从中移除这些倍数数字的列表。The first list contains the numbers whose multiples will be removed, and the second list is the list from which to remove the numbers. 以下示例中的代码使用此递归函数来消除列表中的所有非质数,结果是得到一个质数列表。The code in the following example uses this recursive function to eliminate all the non-prime numbers from a list, leaving a list of prime numbers as the result.

let IsPrimeMultipleTest n x =
   x = n || x % n <> 0

let rec RemoveAllMultiples listn listx =
   match listn with
   | head :: tail -> RemoveAllMultiples tail (List.filter (IsPrimeMultipleTest head) listx)
   | [] -> listx


let GetPrimesUpTo n =
    let max = int (sqrt (float n))
    RemoveAllMultiples [ 2 .. max ] [ 1 .. n ]

printfn "Primes Up To %d:\n %A" 100 (GetPrimesUpTo 100)

输出如下所示:The output is as follows:

Primes Up To 100:
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; 73; 79; 83; 89; 97]

模块函数Module Functions

List 模块提供了用于访问列表元素的函数。The List module provides functions that access the elements of a list. 访问头元素的速度最快且最为容易。The head element is the fastest and easiest to access. 使用属性 head 或模块函数 列表 headUse the property Head or the module function List.head. 您可以使用 tail 属性或 list tail 函数访问列表的尾部。You can access the tail of a list by using the Tail property or the List.tail function. 若要按索引查找元素,请使用 List n 函数。To find an element by index, use the List.nth function. List.nth 将遍历列表。List.nth traverses the list. 因此,它是 O (n) 。Therefore, it is O(n). 如果你的代码经常使用 List.nth,那么可能需要考虑使用数组而不是列表。If your code uses List.nth frequently, you might want to consider using an array instead of a list. 数组中的元素访问的运算复杂度为 O(1)。Element access in arrays is O(1).

针对列表的布尔操作Boolean Operations on Lists

IsEmpty函数确定列表是否包含任何元素。The List.isEmpty function determines whether a list has any elements.

List exists函数向列表的元素应用布尔测试,并在 true 有任何元素满足测试时返回。The List.exists function applies a Boolean test to elements of a list and returns true if any element satisfies the test. Array.exists2 类似于,但操作在两个列表中连续的元素对。List.exists2 is similar but operates on successive pairs of elements in two lists.

以下代码演示了 List.exists 的用法。The following code demonstrates the use of List.exists.

// Use List.exists to determine whether there is an element of a list satisfies a given Boolean expression.
// containsNumber returns true if any of the elements of the supplied list match
// the supplied number.
let containsNumber number list = List.exists (fun elem -> elem = number) list
let list0to3 = [0 .. 3]
printfn "For list %A, contains zero is %b" list0to3 (containsNumber 0 list0to3)

输出如下所示:The output is as follows:

For list [0; 1; 2; 3], contains zero is true

以下示例演示了 List.exists2 的用法。The following example demonstrates the use of List.exists2.

// Use List.exists2 to compare elements in two lists.
// isEqualElement returns true if any elements at the same position in two supplied
// lists match.
let isEqualElement list1 list2 = List.exists2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
let list1to5 = [ 1 .. 5 ]
let list5to1 = [ 5 .. -1 .. 1 ]
if (isEqualElement list1to5 list5to1) then
    printfn "Lists %A and %A have at least one equal element at the same position." list1to5 list5to1
else
    printfn "Lists %A and %A do not have an equal element at the same position." list1to5 list5to1

输出如下所示:The output is as follows:

Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.

如果要测试列表中的所有元素是否都满足条件,可以使用 forallYou can use List.forall if you want to test whether all the elements of a list meet a condition.

let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list
printfn "%b" (isAllZeroes [0.0; 0.0])
printfn "%b" (isAllZeroes [0.0; 1.0])

输出如下所示:The output is as follows:

true
false

同样, array.forall2 确定两个列表中相应位置的所有元素是否都满足涉及每对元素的布尔表达式。Similarly, List.forall2 determines whether all elements in the corresponding positions in two lists satisfy a Boolean expression that involves each pair of elements.

let listEqual list1 list2 = List.forall2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
printfn "%b" (listEqual [0; 1; 2] [0; 1; 2])
printfn "%b" (listEqual [0; 0; 0] [0; 1; 0])

输出如下所示:The output is as follows:

true
false

针对列表的排序操作Sort Operations on Lists

ListsortByarray.sortwith函数对列表进行排序。The List.sort, List.sortBy, and List.sortWith functions sort lists. 排序函数可确定要使用上面三个函数中的哪一个函数。The sorting function determines which of these three functions to use. List.sort 使用默认的泛型比较。List.sort uses default generic comparison. 泛型比较根据泛型比较函数使用全局运算符来比较值。Generic comparison uses global operators based on the generic compare function to compare values. 它能够有效地处理各种元素类型,例如简单数值类型、元组、记录、可区分联合、列表、数组以及任何实现 System.IComparable 的类型。It works efficiently with a wide variety of element types, such as simple numeric types, tuples, records, discriminated unions, lists, arrays, and any type that implements System.IComparable. 对于实现 System.IComparable 的类型,泛型比较将使用 System.IComparable.CompareTo() 函数。For types that implement System.IComparable, generic comparison uses the System.IComparable.CompareTo() function. 泛型比较还可处理字符串,只不过使用的是不依赖于区域性的排序顺序。Generic comparison also works with strings, but uses a culture-independent sorting order. 不应对不支持的类型(例如函数类型)使用泛型比较。Generic comparison should not be used on unsupported types, such as function types. 此外,默认泛型比较的性能最适用于小型结构化类型;对于需要经常比较和排序的大型结构化类型,请考虑实现 System.IComparable 并提供 System.IComparable.CompareTo() 方法的有效实现。Also, the performance of the default generic comparison is best for small structured types; for larger structured types that need to be compared and sorted frequently, consider implementing System.IComparable and providing an efficient implementation of the System.IComparable.CompareTo() method.

List.sortBy 使用一个函数,此函数返回一个用作排序条件的值,而 List.sortWith 将比较函数用作参数。List.sortBy takes a function that returns a value that is used as the sort criterion, and List.sortWith takes a comparison function as an argument. 当你使用不支持比较的类型或比较需要更复杂的比较语义(对于区域性识别字符串)时,后面这两个函数会很有用。These latter two functions are useful when you are working with types that do not support comparison, or when the comparison requires more complex comparison semantics, as in the case of culture-aware strings.

以下示例演示了 List.sort 的用法。The following example demonstrates the use of List.sort.

let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1

输出如下所示:The output is as follows:

[-2; 1; 4; 5; 8]

以下示例演示了 List.sortBy 的用法。The following example demonstrates the use of List.sortBy.

let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2

输出如下所示:The output is as follows:

[1; -2; 4; 5; 8]

下一个示例演示了 List.sortWith 的用法。The next example demonstrates the use of List.sortWith. 在此示例中,使用自定义比较函数 compareWidgets 首先比较自定义类型的一个字段,在第一个字段的值相等的情况下,再比较另一个字段。In this example, the custom comparison function compareWidgets is used to first compare one field of a custom type, and then another when the values of the first field are equal.

type Widget = { ID: int; Rev: int }

let compareWidgets widget1 widget2 =
   if widget1.ID < widget2.ID then -1 else
   if widget1.ID > widget2.ID then 1 else
   if widget1.Rev < widget2.Rev then -1 else
   if widget1.Rev > widget2.Rev then 1 else
   0

let listToCompare = [
    { ID = 92; Rev = 1 }
    { ID = 110; Rev = 1 }
    { ID = 100; Rev = 5 }
    { ID = 100; Rev = 2 }
    { ID = 92; Rev = 1 }
    ]

let sortedWidgetList = List.sortWith compareWidgets listToCompare
printfn "%A" sortedWidgetList

输出如下所示:The output is as follows:

[{ID = 92;
Rev = 1;}; {ID = 92;
Rev = 1;}; {ID = 100;
Rev = 2;}; {ID = 100;
Rev = 5;}; {ID = 110;
Rev = 1;}]

针对列表的搜索操作Search Operations on Lists

可以对列表执行各种搜索操作。Numerous search operations are supported for lists. 最简单的 列表查找可用于查找与给定条件匹配的第一个元素。The simplest, List.find, enables you to find the first element that matches a given condition.

以下代码示例演示了如何使用 List.find 来查找列表中可被 5 整除的第一个元素。The following code example demonstrates the use of List.find to find the first number that is divisible by 5 in a list.

let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result

结果为 5。The result is 5.

如果必须首先转换元素,请调用 List. pick,它采用一个返回选项的函数,并查找的第一个选项值为 Some(x)If the elements must be transformed first, call List.pick, which takes a function that returns an option, and looks for the first option value that is Some(x). List.pick 返回结果 x,而不是返回元素。Instead of returning the element, List.pick returns the result x. 如果未找到匹配的元素,则 List.pick 将引发 System.Collections.Generic.KeyNotFoundExceptionIf no matching element is found, List.pick throws System.Collections.Generic.KeyNotFoundException. 以下代码显示了 List.pick 的用法。The following code shows the use of List.pick.

let valuesList = [ ("a", 1); ("b", 2); ("c", 3) ]

let resultPick = List.pick (fun elem ->
                    match elem with
                    | (value, 2) -> Some value
                    | _ -> None) valuesList
printfn "%A" resultPick

输出如下所示:The output is as follows:

"b"

另一组搜索操作、 tryFind 和相关函数返回一个选项值。Another group of search operations, List.tryFind and related functions, return an option value. List.tryFind 函数返回列表中满足条件的第一个元素(如果该元素存在);如果该元素不存在,则返回选项值 NoneThe List.tryFind function returns the first element of a list that satisfies a condition if such an element exists, but the option value None if not. 变体 列表。 如果找到元素,则为 array.tryfindindex 返回元素的索引,而不是元素本身。The variation List.tryFindIndex returns the index of the element, if one is found, rather than the element itself. 下面的代码中阐释了这些函数。These functions are illustrated in the following code.

let list1d = [1; 3; 7; 9; 11; 13; 15; 19; 22; 29; 36]
let isEven x = x % 2 = 0
match List.tryFind isEven list1d with
| Some value -> printfn "The first even value is %d." value
| None -> printfn "There is no even value in the list."

match List.tryFindIndex isEven list1d with
| Some value -> printfn "The first even value is at position %d." value
| None -> printfn "There is no even value in the list."

输出如下所示:The output is as follows:

The first even value is 22.
The first even value is at position 8.

针对列表的算术运算Arithmetic Operations on Lists

常见算术运算(如 sum 和 average)内置于 列表模块中。Common arithmetic operations such as sum and average are built into the List module. 若要使用 list. sum,List 元素类型必须支持 + 运算符并且值为零。To work with List.sum, the list element type must support the + operator and have a zero value. 所有内置算术类型都满足这些条件。All built-in arithmetic types satisfy these conditions. 若要使用 List,元素类型必须支持不含余数的除法,这会排除整数类型但允许浮点类型。To work with List.average, the element type must support division without a remainder, which excludes integral types but allows for floating point types. SumByaverageBy函数将函数作为参数使用,此函数的结果用于计算 sum 或 average 的值。The List.sumBy and List.averageBy functions take a function as a parameter, and this function's results are used to calculate the values for the sum or average.

以下代码演示了 List.sumList.sumByList.average 的用法。The following code demonstrates the use of List.sum, List.sumBy, and List.average.

// Compute the sum of the first 10 integers by using List.sum.
let sum1 = List.sum [1 .. 10]

// Compute the sum of the squares of the elements of a list by using List.sumBy.
let sum2 = List.sumBy (fun elem -> elem*elem) [1 .. 10]

// Compute the average of the elements of a list by using List.average.
let avg1 = List.average [0.0; 1.0; 1.0; 2.0]

printfn "%f" avg1

输出为 1.000000The output is 1.000000.

以下代码显示了 List.averageBy 的用法。The following code shows the use of List.averageBy.

let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2

输出为 5.5The output is 5.5.

列表和元组Lists and Tuples

包含元组的列表可由压缩和解压缩函数操作。Lists that contain tuples can be manipulated by zip and unzip functions. 这些函数将两个包含单值的列表合并为一个元组列表,或将一个元组列表分成两个包含单值的列表。These functions combine two lists of single values into one list of tuples or separate one list of tuples into two lists of single values. 最简单的 List.zip 函数使用单个元素的两个列表,并生成一个元组对列表。The simplest List.zip function takes two lists of single elements and produces a single list of tuple pairs. 另一个版本( List.zip3)采用单个元素的三个列表,并生成包含三个元素的元组的单个列表。Another version, List.zip3, takes three lists of single elements and produces a single list of tuples that have three elements. 以下代码示例演示了 List.zip 的用法。The following code example demonstrates the use of List.zip.

let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip

输出如下所示:The output is as follows:

[(1, -1); (2, -2); (3; -3)]

以下代码示例演示了 List.zip3 的用法。The following code example demonstrates the use of List.zip3.

let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3

输出如下所示:The output is as follows:

[(1, -1, 0); (2, -2, 0); (3, -3, 0)]

对应的解压缩版本( list.unzip3 )采用元组的列表并返回元组中的列表,其中,第一个列表包含每个元组中的第一个元素,第二个列表包含每个元组的第二个元素,依此类推。The corresponding unzip versions, List.unzip and List.unzip3, take lists of tuples and return lists in a tuple, where the first list contains all the elements that were first in each tuple, and the second list contains the second element of each tuple, and so on.

下面的代码示例演示如何使用列表。The following code example demonstrates the use of List.unzip.

let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)

输出如下所示:The output is as follows:

([1; 3], [2; 4])
[1; 3] [2; 4]

下面的代码示例演示如何使用 list.unzip3The following code example demonstrates the use of List.unzip3.

let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3

输出如下所示:The output is as follows:

([1; 4], [2; 5], [3; 6])

针对列表元素的操作Operating on List Elements

F# 支持针对列表元素执行各种操作。F# supports a variety of operations on list elements. 最简单的是 iter,它使你可以对列表的每个元素调用函数。The simplest is List.iter, which enables you to call a function on every element of a list. 变体包括array.iter2,它使你能够对两个列表的元素执行操作, array.iteri,这类似于, List.iter 只不过每个元素的索引将作为参数传递给为每个元素调用的函数和list.iteri2,这是和功能的组合。 List.iter2 List.iteriVariations include List.iter2, which enables you to perform an operation on elements of two lists, List.iteri, which is like List.iter except that the index of each element is passed as an argument to the function that is called for each element, and List.iteri2, which is a combination of the functionality of List.iter2 and List.iteri. 以下代码示例阐释了这些函数。The following code example illustrates these functions.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
List.iter (fun x -> printfn "List.iter: element is %d" x) list1
List.iteri(fun i x -> printfn "List.iteri: element %d is %d" i x) list1
List.iter2 (fun x y -> printfn "List.iter2: elements are %d %d" x y) list1 list2
List.iteri2 (fun i x y ->
                printfn "List.iteri2: element %d of list1 is %d element %d of list2 is %d"
                  i x i y)
            list1 list2

输出如下所示:The output is as follows:

List.iter: element is 1
List.iter: element is 2
List.iter: element is 3
List.iteri: element 0 is 1
List.iteri: element 1 is 2
List.iteri: element 2 is 3
List.iter2: elements are 1 4
List.iter2: elements are 2 5
List.iter2: elements are 3 6
List.iteri2: element 0 of list1 is 1; element 0 of list2 is 4
List.iteri2: element 1 of list1 is 2; element 1 of list2 is 5
List.iteri2: element 2 of list1 is 3; element 2 of list2 is 6

转换列表元素的另一个常用函数是 list,这使你可以将函数应用于列表的每个元素,并将所有结果放入新列表中。Another frequently used function that transforms list elements is List.map, which enables you to apply a function to each element of a list and put all the results into a new list. Array.map2list.map3 是采用多个列表的变体。List.map2 and List.map3 are variations that take multiple lists. 还可以使用list.mapi2,如果除了元素外,还需要将每个元素的索引传递给函数。You can also use List.mapi and List.mapi2, if, in addition to the element, the function needs to be passed the index of each element. List.mapi2List.mapi 之间的唯一区别在于 List.mapi2 使用了两个列表。The only difference between List.mapi2 and List.mapi is that List.mapi2 works with two lists. 下面的示例阐释了List。The following example illustrates List.map.

let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList

输出如下所示:The output is as follows:

[2; 3; 4]

以下示例演示如何使用 List.map2The following example shows the use of List.map2.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
let sumList = List.map2 (fun x y -> x + y) list1 list2
printfn "%A" sumList

输出如下所示:The output is as follows:

[5; 7; 9]

以下示例演示如何使用 List.map3The following example shows the use of List.map3.

let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2

输出如下所示:The output is as follows:

[7; 10; 13]

以下示例演示如何使用 List.mapiThe following example shows the use of List.mapi.

let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex

输出如下所示:The output is as follows:

[1; 3; 5]

以下示例演示如何使用 List.mapi2The following example shows the use of List.mapi2.

let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex

输出如下所示:The output is as follows:

[0; 7; 18]

List. collect 类似于 List.map ,只不过每个元素都生成一个列表,并将所有这些列表连接到一个最终列表。List.collect is like List.map, except that each element produces a list and all these lists are concatenated into a final list. 在以下代码中,列表的每个元素均生成三个数字。In the following code, each element of the list generates three numbers. 所有这些数字将收集到一个列表中。These are all collected into one list.

let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList

输出如下所示:The output is as follows:

[1; 2; 3; 2; 4; 6; 3; 6; 9]

你还可以使用 List. filter,它采用布尔条件,并生成仅包含满足给定条件的元素的新列表。You can also use List.filter, which takes a Boolean condition and produces a new list that consists only of elements that satisfy the given condition.

let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]

生成的列表为 [2; 4; 6]The resulting list is [2; 4; 6].

Map 和 filter,List 的组合 。选择 使您能够同时转换和选择元素。A combination of map and filter, List.choose enables you to transform and select elements at the same time. List.choose 对列表的每个元素应用一个返回选项的函数,并在该函数返回选项值 Some 时为元素返回新的结果列表。List.choose applies a function that returns an option to each element of a list, and returns a new list of the results for elements when the function returns the option value Some.

以下代码演示了如何使用 List.choose 从单词列表中选择大写单词。The following code demonstrates the use of List.choose to select capitalized words out of a list of words.

let listWords = [ "and"; "Rome"; "Bob"; "apple"; "zebra" ]
let isCapitalized (string1:string) = System.Char.IsUpper string1.[0]
let results = List.choose (fun elem ->
    match elem with
    | elem when isCapitalized elem -> Some(elem + "'s")
    | _ -> None) listWords
printfn "%A" results

输出如下所示:The output is as follows:

["Rome's"; "Bob's"]

针对多个列表的操作Operating on Multiple Lists

可以将多个列表联接在一起。Lists can be joined together. 若要将两个列表联接为一个列表,请使用List。To join two lists into one, use List.append. 若要加入两个以上的列表,请使用列表。To join more than two lists, use List.concat.

let list1to10 = List.append [1; 2; 3] [4; 5; 6; 7; 8; 9; 10]
let listResult = List.concat [ [1; 2; 3]; [4; 5; 6]; [7; 8; 9] ]
List.iter (fun elem -> printf "%d " elem) list1to10
printfn ""
List.iter (fun elem -> printf "%d " elem) listResult

Fold 和 Scan 操作Fold and Scan Operations

一些列表操作涉及所有列表元素之间的相互依赖关系。Some list operations involve interdependencies between all of the list elements. 折叠和扫描操作类似于, List.iter List.map 在中,您对每个元素调用一个函数,但这些操作提供了一个名为 累加器 的附加参数,该参数通过计算传递信息。The fold and scan operations are like List.iter and List.map in that you invoke a function on each element, but these operations provide an additional parameter called the accumulator that carries information through the computation.

使用 List.fold 可对列表执行计算。Use List.fold to perform a calculation on a list.

下面的代码示例演示如何使用 List 进行各种操作。The following code example demonstrates the use of List.fold to perform various operations.

将遍历列表;累加器 acc 是一个在计算过程中不断传递的值。The list is traversed; the accumulator acc is a value that is passed along as the calculation proceeds. 第一个参数采用累加器和列表元素,并返回针对列表元素的计算的中间结果。The first argument takes the accumulator and the list element, and returns the interim result of the calculation for that list element. 第二个自变量为累加器的初始值。The second argument is the initial value of the accumulator.

let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 3 ] (sumList [ 1 .. 3 ])

// The following example computes the average of a list.
let averageList list = (List.fold (fun acc elem -> acc + float elem) 0.0 list / float list.Length)

// The following example computes the standard deviation of a list.
// The standard deviation is computed by taking the square root of the
// sum of the variances, which are the differences between each value
// and the average.
let stdDevList list =
    let avg = averageList list
    sqrt (List.fold (fun acc elem -> acc + (float elem - avg) ** 2.0 ) 0.0 list / float list.Length)

let testList listTest =
    printfn "List %A average: %f stddev: %f" listTest (averageList listTest) (stdDevList listTest)

testList [1; 1; 1]
testList [1; 2; 1]
testList [1; 2; 3]

// List.fold is the same as to List.iter when the accumulator is not used.
let printList list = List.fold (fun acc elem -> printfn "%A" elem) () list
printList [0.0; 1.0; 2.5; 5.1 ]

// The following example uses List.fold to reverse a list.
// The accumulator starts out as the empty list, and the function uses the cons operator
// to add each successive element to the head of the accumulator list, resulting in a
// reversed form of the list.
let reverseList list = List.fold (fun acc elem -> elem::acc) [] list
printfn "%A" (reverseList [1 .. 10])

这些函数的各个版本(函数名中有一个数字)对多个列表执行操作。The versions of these functions that have a digit in the function name operate on more than one list. 例如, list.fold2 对两个列表执行计算。For example, List.fold2 performs computations on two lists.

以下示例演示了 List.fold2 的用法。The following example demonstrates the use of List.fold2.

// Use List.fold2 to perform computations over two lists (of equal size) at the same time.
// Example: Sum the greater element at each list position.
let sumGreatest list1 list2 = List.fold2 (fun acc elem1 elem2 ->
                                              acc + max elem1 elem2) 0 list1 list2

let sum = sumGreatest [1; 2; 3] [3; 2; 1]
printfn "The sum of the greater of each pair of elements in the two lists is %d." sum

List.fold列表。 中的扫描不同于 List.fold 返回额外参数的最终值,而 List.scan 是返回中间值的列表 (以及额外参数) 的最终值。List.fold and List.scan differ in that List.fold returns the final value of the extra parameter, but List.scan returns the list of the intermediate values (along with the final value) of the extra parameter.

其中每个函数都包含反向变体(例如 list.foldback),这不同于列表的遍历顺序和参数的顺序。Each of these functions includes a reverse variation, for example, List.foldBack, which differs in the order in which the list is traversed and the order of the arguments. 另外, List.foldList.foldBack 具有变体、 list.fold2array.foldback2,这两个列表的长度相等。Also, List.fold and List.foldBack have variations, List.fold2 and List.foldBack2, that take two lists of equal length. 对每个元素执行的函数可以使用两个列表的对应元素来执行一些操作。The function that executes on each element can use corresponding elements of both lists to perform some action. 两个列表的元素类型可以不同(如以下示例所示),其中一个列表包含银行帐户的交易金额,而另一个列表包含交易的类型:存款或取款。The element types of the two lists can be different, as in the following example, in which one list contains transaction amounts for a bank account, and the other list contains the type of transaction: deposit or withdrawal.

// Discriminated union type that encodes the transaction type.
type Transaction =
    | Deposit
    | Withdrawal

let transactionTypes = [Deposit; Deposit; Withdrawal]
let transactionAmounts = [100.00; 1000.00; 95.00 ]
let initialBalance = 200.00

// Use fold2 to perform a calculation on the list to update the account balance.
let endingBalance = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2)
                                initialBalance
                                transactionTypes
                                transactionAmounts
printfn "%f" endingBalance

对于类似于求和这样的计算,List.foldList.foldBack 具有相同的效果,因为结果不依赖于遍历顺序。For a calculation like summation, List.fold and List.foldBack have the same effect because the result does not depend on the order of traversal. 在以下示例中,List.foldBack 用于在列表中添加元素。In the following example, List.foldBack is used to add the elements in a list.

let sumListBack list = List.foldBack (fun elem acc -> acc + elem) list 0
printfn "%d" (sumListBack [1; 2; 3])

// For a calculation in which the order of traversal is important, fold and foldBack have different
// results. For example, replacing fold with foldBack in the listReverse function
// produces a function that copies the list, rather than reversing it.
let copyList list = List.foldBack (fun elem acc -> elem::acc) list []
printfn "%A" (copyList [1 .. 10])

以下示例将返回到银行帐户示例。The following example returns to the bank account example. 这次,添加一个新的事务类型:利息计算。This time a new transaction type is added: an interest calculation. 期末余额现在取决于交易顺序。The ending balance now depends on the order of transactions.

type Transaction2 =
    | Deposit
    | Withdrawal
    | Interest

let transactionTypes2 = [Deposit; Deposit; Withdrawal; Interest]
let transactionAmounts2 = [100.00; 1000.00; 95.00; 0.05 / 12.0 ]
let initialBalance2 = 200.00

// Because fold2 processes the lists by starting at the head element,
// the interest is calculated last, on the balance of 1205.00.
let endingBalance2 = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                initialBalance2
                                transactionTypes2
                                transactionAmounts2
printfn "%f" endingBalance2


// Because foldBack2 processes the lists by starting at end of the list,
// the interest is calculated first, on the balance of only 200.00.
let endingBalance3 = List.foldBack2 (fun elem1 elem2 acc ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                transactionTypes2
                                transactionAmounts2
                                initialBalance2
printfn "%f" endingBalance3

函数 列表 类似于 List.foldList.scan ,只不过只 List.reduce 需使用元素类型的两个自变量(而不是一个),而是使用一个函数,该函数采用元素类型的两个参数而不是一个参数,这意味着它将存储计算的中间结果。The function List.reduce is somewhat like List.fold and List.scan, except that instead of passing around a separate accumulator, List.reduce takes a function that takes two arguments of the element type instead of just one, and one of those arguments acts as the accumulator, meaning that it stores the intermediate result of the computation. List.reduce 首先对前两个列表元素执行操作,然后将操作的结果和下一个元素一起使用。List.reduce starts by operating on the first two list elements, and then uses the result of the operation along with the next element. 由于不存在具有自己的类型的单独累加器,因此只可以在累加器和元素类型的类型相同时,使用 List.reduce 代替 List.foldBecause there is not a separate accumulator that has its own type, List.reduce can be used in place of List.fold only when the accumulator and the element type have the same type. 以下代码演示了 List.reduce 的用法。The following code demonstrates the use of List.reduce. 如果提供的列表中不包含任何元素,则 List.reduce 将引发异常。List.reduce throws an exception if the list provided has no elements.

在以下代码中,对 lambda 表达式的第一个调用提供了自变量 2 和 4,并返回 6;下一个调用提供了自变量 6 和 10,因此结果为 16。In the following code, the first call to the lambda expression is given the arguments 2 and 4, and returns 6, and the next call is given the arguments 6 and 10, so the result is 16.

let sumAList list =
    try
        List.reduce (fun acc elem -> acc + elem) list
    with
       | :? System.ArgumentException as exc -> 0

let resultSum = sumAList [2; 4; 10]
printfn "%d " resultSum

在列表和其他集合类型之间进行转换Converting Between Lists and Other Collection Types

List 模块提供了用于来回转换序列和数组的函数。The List module provides functions for converting to and from both sequences and arrays. 若要转换为序列,请使用 list.toseqlist.ofseqTo convert to or from a sequence, use List.toSeq or List.ofSeq. 若要转换为数组,请使用 toArraylist.ofarrayTo convert to or from an array, use List.toArray or List.ofArray.

其他操作Additional Operations

有关列表中其他操作的信息,请参阅库参考主题 列表模块For information about additional operations on lists, see the library reference topic List Module.

另请参阅See also