序列Sequences

序列是所有类型的元素的逻辑系列。A sequence is a logical series of elements all of one type. 如果有大量的有序数据集合,但不一定需要使用所有元素,则序列将特别有用。Sequences are particularly useful when you have a large, ordered collection of data but do not necessarily expect to use all of the elements. 单个序列元素只会根据需要计算,因此,在不使用所有元素的情况下,序列可提供比列表更好的性能。Individual sequence elements are computed only as required, so a sequence can provide better performance than a list in situations in which not all the elements are used. 序列由 seq<'T> 类型表示,该类型是的别名 IEnumerable<T>Sequences are represented by the seq<'T> type, which is an alias for IEnumerable<T>. 因此,实现接口的任何 .NET 类型 IEnumerable<T> 都可用作序列。Therefore, any .NET type that implements IEnumerable<T> interface can be used as a sequence. Seq 模块为涉及序列的操作提供支持。The Seq module provides support for manipulations involving sequences.

序列表达式Sequence Expressions

序列表达式是计算结果为序列的表达式。A sequence expression is an expression that evaluates to a sequence. 序列表达式可以采用多种形式。Sequence expressions can take a number of forms. 最简单的形式是指定一个范围。The simplest form specifies a range. 例如, seq { 1 .. 5 } 创建一个包含五个元素的序列,包括终结点1和5。For example, seq { 1 .. 5 } creates a sequence that contains five elements, including the endpoints 1 and 5. 您还可以指定增量 (或减量) 两个双句点之间。You can also specify an increment (or decrement) between two double periods. 例如,下面的代码创建10的倍数序列。For example, the following code creates the sequence of multiples of 10.

// Sequence that has an increment.
seq { 0 .. 10 .. 100 }

序列表达式由生成序列值的 F # 表达式组成。Sequence expressions are made up of F# expressions that produce values of the sequence. 还可以通过编程方式生成值:You can also generate values programmatically:

seq { for i in 1 .. 10 -> i * i }

前面的示例使用 -> 运算符,这允许您指定一个表达式,该表达式的值将成为序列的一部分。The previous sample uses the -> operator, which allows you to specify an expression whose value will become a part of the sequence. -> 当其后的代码的每个部分都返回值时,才能使用。You can only use -> if every part of the code that follows it returns a value.

另外,还可以指定 do 关键字,其中包含以下选项 yieldAlternatively, you can specify the do keyword, with an optional yield that follows:

seq { for i in 1 .. 10 do yield i * i }

// The 'yield' is implicit and doesn't need to be specified in most cases.
seq { for i in 1 .. 10 do i * i }

下面的代码将生成一个坐标对列表,以及一个表示该网格的数组的索引。The following code generates a list of coordinate pairs along with an index into an array that represents the grid. 请注意,第一个 for 表达式需要 do 指定。Note that the first for expression requires a do to be specified.

let (height, width) = (10, 10)

seq {
    for row in 0 .. width - 1 do
        for col in 0 .. height - 1 ->
            (row, col, row*width + col)
    }

if序列中使用的表达式是筛选器。An if expression used in a sequence is a filter. 例如,若要生成一个仅包含质数的序列,假设你有一个 isprime 类型的函数 int -> bool ,请按如下所示构造序列。For example, to generate a sequence of only prime numbers, assuming that you have a function isprime of type int -> bool, construct the sequence as follows.

seq { for n in 1 .. 100 do if isprime n then n }

如前文所述, do 此处是必需的,因为没有 else 与一起的分支 ifAs mentioned previously, do is required here because there is no else branch that goes with the if. 如果你尝试使用 -> ,将收到一条错误消息,指出并非所有分支都返回值。If you try to use ->, you'll get an error saying that not all branches return a value.

yield! 关键字The yield! keyword

有时,你可能希望将一系列元素包含在另一个序列中。Sometimes, you may wish to include a sequence of elements into another sequence. 若要在另一个序列内包含序列,需要使用 yield! 关键字:To include a sequence within another sequence, you'll need to use the yield! keyword:

// Repeats '1 2 3 4 5' ten times
seq {
    for _ in 1..10 do
        yield! seq { 1; 2; 3; 4; 5}
}

考虑到的另一种方法 yield! 是将内部序列平展,然后将其包含在包含序列中。Another way of thinking of yield! is that it flattens an inner sequence and then includes that in the containing sequence.

yield!在表达式中使用时,所有其他单个值必须使用 yield 关键字:When yield! is used in an expression, all other single values must use the yield keyword:

// Combine repeated values with their values
seq {
    for x in 1..10 do
        yield x
        yield! seq { for i in 1..x -> i}
}

前面的示例将生成的值, x 以及从到的的所有 1x xThe previous example will produce the value of x in addition to all values from 1 to x for each x.

示例Examples

第一个示例使用包含迭代、筛选器和 yield 的序列表达式来生成数组。The first example uses a sequence expression that contains an iteration, a filter, and a yield to generate an array. 此代码会将1到100之间的质数序列输出到控制台。This code prints a sequence of prime numbers between 1 and 100 to the console.

// Recursive isprime function.
let isprime n =
    let rec check i =
        i > n/2 || (n % i <> 0 && check (i + 1))
    check 2

let aSequence =
    seq {
        for n in 1..100 do
            if isprime n then
                n
    }

for x in aSequence do
    printfn "%d" x

下面的示例创建一个乘法表,其中包含三个元素的元组,每个元素包含两个因素和产品:The following example creates a multiplication table that consists of tuples of three elements, each consisting of two factors and the product:

let multiplicationTable =
    seq {
        for i in 1..9 do
            for j in 1..9 ->
                (i, j, i*j)
    }

下面的示例演示 yield! 如何使用将各个序列合并为一个最终序列。The following example demonstrates the use of yield! to combine individual sequences into a single final sequence. 在这种情况下,将在一个递归函数中串联二元树中每个子树的序列,以生成最终序列。In this case, the sequences for each subtree in a binary tree are concatenated in a recursive function to produce the final sequence.

// Yield the values of a binary tree in a sequence.
type Tree<'a> =
   | Tree of 'a * Tree<'a> * Tree<'a>
   | Leaf of 'a

// inorder : Tree<'a> -> seq<'a>
let rec inorder tree =
    seq {
      match tree with
          | Tree(x, left, right) ->
               yield! inorder left
               yield x
               yield! inorder right
          | Leaf x -> yield x
    }

let mytree = Tree(6, Tree(2, Leaf(1), Leaf(3)), Leaf(9))
let seq1 = inorder mytree
printfn "%A" seq1

使用序列Using Sequences

序列支持许多与 列表相同的函数。Sequences support many of the same functions as lists. 序列还支持通过使用键生成函数进行分组和计数等操作。Sequences also support operations such as grouping and counting by using key-generating functions. 序列还支持用于提取个子序列的更广泛的函数。Sequences also support more diverse functions for extracting subsequences.

许多数据类型(例如列表、数组、集和映射)都是隐式的,因为它们是可枚举的集合。Many data types, such as lists, arrays, sets, and maps are implicitly sequences because they are enumerable collections. 采用序列作为参数的函数除了实现的任何 .NET 数据类型外,还适用于任何常见的 F # 数据类型 System.Collections.Generic.IEnumerable<'T>A function that takes a sequence as an argument works with any of the common F# data types, in addition to any .NET data type that implements System.Collections.Generic.IEnumerable<'T>. 将此与采用列表作为参数的函数相反,只能采用列表。Contrast this to a function that takes a list as an argument, which can only take lists. 类型 seq<'T> 是的类型缩写 IEnumerable<'T>The type seq<'T> is a type abbreviation for IEnumerable<'T>. 这意味着,实现泛型的任何类型 System.Collections.Generic.IEnumerable<'T> (包括数组、列表、集和 F # 中的映射)以及大多数 .net 集合类型都与类型兼容, seq 可在需要序列的任何位置使用。This means that any type that implements the generic System.Collections.Generic.IEnumerable<'T>, which includes arrays, lists, sets, and maps in F#, and also most .NET collection types, is compatible with the seq type and can be used wherever a sequence is expected.

模块函数Module Functions

Fsharp.core 命名空间中的Seq 模块包含用于处理序列的函数。The Seq module in the FSharp.Collections namespace contains functions for working with sequences. 这些函数也适用于列表、数组、映射和集,因为这些类型都是可枚举的,因此可以视为序列。These functions work with lists, arrays, maps, and sets as well, because all of those types are enumerable, and therefore can be treated as sequences.

创建序列Creating Sequences

您可以使用序列表达式(如前文所述)或使用特定函数来创建序列。You can create sequences by using sequence expressions, as described previously, or by using certain functions.

您可以通过使用 序列 empty创建一个空序列,也可以通过使用 seq. singleton创建只具有一个指定元素的序列。You can create an empty sequence by using Seq.empty, or you can create a sequence of just one specified element by using Seq.singleton.

let seqEmpty = Seq.empty
let seqOne = Seq.singleton 10

您可以使用 Seq.init 创建使用您提供的函数为其创建元素的序列。You can use Seq.init to create a sequence for which the elements are created by using a function that you provide. 还可为序列提供大小。You also provide a size for the sequence. 此函数与 List.init类似,只是在遍历序列之前不会创建元素。This function is just like List.init, except that the elements are not created until you iterate through the sequence. 下面的代码演示如何使用 Seq.initThe following code illustrates the use of Seq.init.

let seqFirst5MultiplesOf10 = Seq.init 5 (fun n -> n * 10)
Seq.iter (fun elem -> printf "%d " elem) seqFirst5MultiplesOf10

输出为The output is

0 10 20 30 40

通过使用 list.ofarrayarray.oflist< 不> 函数,你可以从数组和列表创建序列。By using Seq.ofArray and Seq.ofList<'T> Function, you can create sequences from arrays and lists. 不过,还可以使用转换运算符将数组和列表转换为序列。However, you can also convert arrays and lists to sequences by using a cast operator. 下面的代码演示了这两种方法。Both techniques are shown in the following code.

// Convert an array to a sequence by using a cast.
let seqFromArray1 = [| 1 .. 10 |] :> seq<int>

// Convert an array to a sequence by using Seq.ofArray.
let seqFromArray2 = [| 1 .. 10 |] |> Seq.ofArray

通过使用 Seq,你可以从弱类型集合中创建一个序列,如中定义的集合 System.CollectionsBy using Seq.cast, you can create a sequence from a weakly typed collection, such as those defined in System.Collections. 此类弱类型集合具有元素类型 System.Object ,并使用非泛型类型进行枚举 System.Collections.Generic.IEnumerable&#96;1Such weakly typed collections have the element type System.Object and are enumerated by using the non-generic System.Collections.Generic.IEnumerable&#96;1 type. 下面的代码演示 Seq.cast 如何使用将转换为 System.Collections.ArrayList 序列。The following code illustrates the use of Seq.cast to convert an System.Collections.ArrayList into a sequence.

open System

let arr = ResizeArray<int>(10)

for i in 1 .. 10 do
    arr.Add(10)

let seqCast = Seq.cast arr

可以通过使用 Seq.initInfinite 函数来定义无限序列。You can define infinite sequences by using the Seq.initInfinite function. 对于这种序列,你提供了一个函数,该函数从元素的索引生成每个元素。For such a sequence, you provide a function that generates each element from the index of the element. 由于延迟计算,可能会出现无限序列;根据需要通过调用指定的函数来创建元素。Infinite sequences are possible because of lazy evaluation; elements are created as needed by calling the function that you specify. 下面的代码示例生成一个无限的浮点数序列,在此示例中,为连续整数的 reciprocals 序列。The following code example produces an infinite sequence of floating point numbers, in this case the alternating series of reciprocals of squares of successive integers.

let seqInfinite =
    Seq.initInfinite (fun index ->
        let n = float (index + 1)
        1.0 / (n * n * (if ((index + 1) % 2 = 0) then 1.0 else -1.0)))

printfn "%A" seqInfinite

Seq: 从采用状态并将其转换为生成序列中每个后续元素的计算函数生成序列。Seq.unfold generates a sequence from a computation function that takes a state and transforms it to produce each subsequent element in the sequence. 状态只是用于计算每个元素的值,并且可以在计算每个元素时进行更改。The state is just a value that is used to compute each element, and can change as each element is computed. 的第二个参数 Seq.unfold 是用于启动序列的初始值。The second argument to Seq.unfold is the initial value that is used to start the sequence. Seq.unfold 将选项类型用于状态,这使你可以通过返回值来终止序列 NoneSeq.unfold uses an option type for the state, which enables you to terminate the sequence by returning the None value. 下面的代码演示了两个序列的示例, seq1 以及 fib 由操作生成的 unfoldThe following code shows two examples of sequences, seq1 and fib, that are generated by an unfold operation. 第一个 seq1 是,它是数字最多为20的简单序列。The first, seq1, is just a simple sequence with numbers up to 20. 第二个 fib 使用 unfold 来计算斐波那契序列。The second, fib, uses unfold to compute the Fibonacci sequence. 因为波那契序列中的每个元素都是前两个斐波那契数的总和,所以,状态值是包含序列中前两个数字的元组。Because each element in the Fibonacci sequence is the sum of the previous two Fibonacci numbers, the state value is a tuple that consists of the previous two numbers in the sequence. 初始值为 (1,1) ,序列中的前两个数字。The initial value is (1,1), the first two numbers in the sequence.

let seq1 =
    0 // Initial state
    |> Seq.unfold (fun state ->
        if (state > 20) then
            None
        else
            Some(state, state + 1))

printfn "The sequence seq1 contains numbers from 0 to 20."

for x in seq1 do
    printf "%d " x

let fib =
    (1, 1) // Initial state
    |> Seq.unfold (fun state ->
        if (snd state > 1000) then
            None
        else
            Some(fst state + snd state, (snd state, fst state + snd state)))

printfn "\nThe sequence fib contains Fibonacci numbers."
for x in fib do printf "%d " x

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

The sequence seq1 contains numbers from 0 to 20.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

The sequence fib contains Fibonacci numbers.

2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

下面的代码示例使用此处所述的许多序列模块函数来生成和计算无限序列的值。The following code is an example that uses many of the sequence module functions described here to generate and compute the values of infinite sequences. 此代码可能需要几分钟才能运行。The code might take a few minutes to run.

// generateInfiniteSequence generates sequences of floating point
// numbers. The sequences generated are computed from the fDenominator
// function, which has the type (int -> float) and computes the
// denominator of each term in the sequence from the index of that
// term. The isAlternating parameter is true if the sequence has
// alternating signs.
let generateInfiniteSequence fDenominator isAlternating =
    if (isAlternating) then
        Seq.initInfinite (fun index ->
            1.0 /(fDenominator index) * (if (index % 2 = 0) then -1.0 else 1.0))
    else
        Seq.initInfinite (fun index -> 1.0 /(fDenominator index))

// The harmonic alternating series is like the harmonic series
// except that it has alternating signs.
let harmonicAlternatingSeries = generateInfiniteSequence (fun index -> float index) true

// This is the series of reciprocals of the odd numbers.
let oddNumberSeries = generateInfiniteSequence (fun index -> float (2 * index - 1)) true

// This is the series of recipocals of the squares.
let squaresSeries = generateInfiniteSequence (fun index -> float (index * index)) false

// This function sums a sequence, up to the specified number of terms.
let sumSeq length sequence =
    (0, 0.0)
    |>
    Seq.unfold (fun state ->
        let subtotal = snd state + Seq.item (fst state + 1) sequence
        if (fst state >= length) then
            None
        else
            Some(subtotal, (fst state + 1, subtotal)))

// This function sums an infinite sequence up to a given value
// for the difference (epsilon) between subsequent terms,
// up to a maximum number of terms, whichever is reached first.
let infiniteSum infiniteSeq epsilon maxIteration =
    infiniteSeq
    |> sumSeq maxIteration
    |> Seq.pairwise
    |> Seq.takeWhile (fun elem -> abs (snd elem - fst elem) > epsilon)
    |> List.ofSeq
    |> List.rev
    |> List.head
    |> snd

// Compute the sums for three sequences that converge, and compare
// the sums to the expected theoretical values.
let result1 = infiniteSum harmonicAlternatingSeries 0.00001 100000
printfn "Result: %f  ln2: %f" result1 (log 2.0)

let pi = Math.PI
let result2 = infiniteSum oddNumberSeries 0.00001 10000
printfn "Result: %f pi/4: %f" result2 (pi/4.0)

// Because this is not an alternating series, a much smaller epsilon
// value and more terms are needed to obtain an accurate result.
let result3 = infiniteSum squaresSeries 0.0000001 1000000
printfn "Result: %f pi*pi/6: %f" result3 (pi*pi/6.0)

搜索和查找元素Searching and Finding Elements

序列支持可用于列表的功能: seq. array.exists2findIndex,seq Seq.findseq, tryFind,,array.tryfindindex. Seq.tryFindIndexSequences support functionality available with lists: Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind, and Seq.tryFindIndex. 可用于序列的这些函数的版本仅计算到所搜索的元素的顺序。The versions of these functions that are available for sequences evaluate the sequence only up to the element that is being searched for. 有关示例,请参阅 列表For examples, see Lists.

获取个子序列Obtaining Subsequences

Seq. filterseq。 choose 类似于列表可用的相应函数,但在计算序列元素之前,不会发生筛选和选择。Seq.filter and Seq.choose are like the corresponding functions that are available for lists, except that the filtering and choosing does not occur until the sequence elements are evaluated.

Seq 从另一个序列创建序列,但将序列限制为指定数量的元素。Seq.truncate creates a sequence from another sequence, but limits the sequence to a specified number of elements. Seq。 take 会 创建一个新序列,该序列只包含序列开头的指定数量的元素。Seq.take creates a new sequence that contains only a specified number of elements from the start of a sequence. 如果序列中的元素少于您指定要执行的元素, Seq.take 则将引发 System.InvalidOperationExceptionIf there are fewer elements in the sequence than you specify to take, Seq.take throws a System.InvalidOperationException. 与之间的区别在于, Seq.take Seq.truncate Seq.truncate 如果元素数少于指定的数目,则不会产生错误。The difference between Seq.take and Seq.truncate is that Seq.truncate does not produce an error if the number of elements is fewer than the number you specify.

下面的代码演示了和之间的行为 Seq.truncate Seq.takeThe following code shows the behavior of and differences between Seq.truncate and Seq.take.

let mySeq = seq { for i in 1 .. 10 -> i*i }
let truncatedSeq = Seq.truncate 5 mySeq
let takenSeq = Seq.take 5 mySeq

let truncatedSeq2 = Seq.truncate 20 mySeq
let takenSeq2 = Seq.take 20 mySeq

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""

// Up to this point, the sequences are not evaluated.
// The following code causes the sequences to be evaluated.
truncatedSeq |> printSeq
truncatedSeq2 |> printSeq
takenSeq |> printSeq
// The following line produces a run-time error (in printSeq):
takenSeq2 |> printSeq

出现错误之前的输出如下所示。The output, before the error occurs, is as follows.

1 4 9 16 25
1 4 9 16 25 36 49 64 81 100
1 4 9 16 25
1 4 9 16 25 36 49 64 81 100

通过使用 takeWhile,你可以 (布尔函数指定一个谓词函数) 并从另一个序列中创建一个序列,该序列由该谓词的原始序列的那些元素组成 true ,但在该谓词返回的第一个元素之前停止 falseBy using Seq.takeWhile, you can specify a predicate function (a Boolean function) and create a sequence from another sequence made up of those elements of the original sequence for which the predicate is true, but stop before the first element for which the predicate returns false. Seq: skip 返回一个序列,该序列跳过另一个序列的指定数目的第一个元素,并返回剩余的元素。Seq.skip returns a sequence that skips a specified number of the first elements of another sequence and returns the remaining elements. SkipWhile 返回一个序列,该序列在谓词返回的情况下跳过另一个序列的第一个元素 true ,然后返回剩余的元素(从该谓词返回的第一个元素开始) falseSeq.skipWhile returns a sequence that skips the first elements of another sequence as long as the predicate returns true, and then returns the remaining elements, starting with the first element for which the predicate returns false.

下面的代码示例演示了、和的行为 Seq.takeWhile Seq.skip Seq.skipWhileThe following code example illustrates the behavior of and differences between Seq.takeWhile, Seq.skip, and Seq.skipWhile.

// takeWhile
let mySeqLessThan10 = Seq.takeWhile (fun elem -> elem < 10) mySeq
mySeqLessThan10 |> printSeq

// skip
let mySeqSkipFirst5 = Seq.skip 5 mySeq
mySeqSkipFirst5 |> printSeq

// skipWhile
let mySeqSkipWhileLessThan10 = Seq.skipWhile (fun elem -> elem < 10) mySeq
mySeqSkipWhileLessThan10 |> printSeq

输出如下所示。The output is as follows.

1 4 9
36 49 64 81 100
16 25 36 49 64 81 100

转换序列Transforming Sequences

Seq。 将创建一个新序列,其中输入序列的连续元素分为元组。Seq.pairwise creates a new sequence in which successive elements of the input sequence are grouped into tuples.

let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""
let seqPairwise = Seq.pairwise (seq { for i in 1 .. 10 -> i*i })
printSeq seqPairwise

printfn ""
let seqDelta = Seq.map (fun elem -> snd elem - fst elem) seqPairwise
printSeq seqDelta

Seq 类似 Seq.pairwise ,只是它会生成一系列数组,其中包含序列中的 窗口) (相邻元素的副本。Seq.windowed is like Seq.pairwise, except that instead of producing a sequence of tuples, it produces a sequence of arrays that contain copies of adjacent elements (a window) from the sequence. 指定每个数组中所需的相邻元素的数目。You specify the number of adjacent elements you want in each array.

以下代码示例演示了 Seq.windowed 的用法。The following code example demonstrates the use of Seq.windowed. 在此示例中,窗口中的元素数为3。In this case the number of elements in the window is 3. 该示例使用 printSeq 上一个代码示例中定义的。The example uses printSeq, which is defined in the previous code example.

let seqNumbers = [ 1.0; 1.5; 2.0; 1.5; 1.0; 1.5 ] :> seq<float>
let seqWindows = Seq.windowed 3 seqNumbers
let seqMovingAverage = Seq.map Array.average seqWindows
printfn "Initial sequence: "
printSeq seqNumbers
printfn "\nWindows of length 3: "
printSeq seqWindows
printfn "\nMoving average: "
printSeq seqMovingAverage

输出如下所示。The output is as follows.

初始顺序:Initial sequence:

1.0 1.5 2.0 1.5 1.0 1.5

Windows of length 3:
[|1.0; 1.5; 2.0|] [|1.5; 2.0; 1.5|] [|2.0; 1.5; 1.0|] [|1.5; 1.0; 1.5|]

Moving average:
1.5 1.666666667 1.5 1.333333333

具有多个序列的操作Operations with Multiple Sequences

Seq.zipSeq.zip3 接受两个或三个序列,并生成元组序列。Seq.zip and Seq.zip3 take two or three sequences and produce a sequence of tuples. 这些函数类似于 列表可用的对应函数。These functions are like the corresponding functions available for lists. 没有相应的功能可将一个序列分隔成两个或更多个序列。There is no corresponding functionality to separate one sequence into two or more sequences. 如果需要为序列使用此功能,请将序列转换为列表,并使用list。If you need this functionality for a sequence, convert the sequence to a list and use List.unzip.

排序、比较和分组Sorting, Comparing, and Grouping

列表支持的排序函数也适用于序列。The sorting functions supported for lists also work with sequences. 这包括 seqsortByThis includes Seq.sort and Seq.sortBy. 这些函数循环访问整个序列。These functions iterate through the whole sequence.

使用 seq.comparewith 函数比较两个序列。You compare two sequences by using the Seq.compareWith function. 函数依次比较连续的元素,并在遇到第一个不相等对时停止。The function compares successive elements in turn, and stops when it encounters the first unequal pair. 任何其他元素不参与比较。Any additional elements do not contribute to the comparison.

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

let sequence1 = seq { 1 .. 10 }
let sequence2 = seq { 10 .. -1 .. 1 }

// Compare two sequences element by element.
let compareSequences =
    Seq.compareWith (fun elem1 elem2 ->
        if elem1 > elem2 then 1
        elif elem1 < elem2 then -1
        else 0)

let compareResult1 = compareSequences sequence1 sequence2
match compareResult1 with
| 1 -> printfn "Sequence1 is greater than sequence2."
| -1 -> printfn "Sequence1 is less than sequence2."
| 0 -> printfn "Sequence1 is equal to sequence2."
| _ -> failwith("Invalid comparison result.")

在前面的代码中,只计算并检查第一个元素,结果为-1。In the previous code, only the first element is computed and examined, and the result is -1.

CountBy 采用一个函数,该函数为每个元素生成一个名为 key 的值。Seq.countBy takes a function that generates a value called a key for each element. 通过对每个元素调用此函数,为每个元素生成一个密钥。A key is generated for each element by calling this function on each element. Seq.countBy 然后返回一个序列,其中包含键值,以及生成每个密钥值的元素数的计数。Seq.countBy then returns a sequence that contains the key values, and a count of the number of elements that generated each value of the key.

let mySeq1 = seq { 1.. 100 }

let printSeq seq1 = Seq.iter (printf "%A ") seq1

let seqResult =
    mySeq1
    |> Seq.countBy (fun elem ->
        if elem % 3 = 0 then 0
        elif elem % 3 = 1 then 1
        else 2)

printSeq seqResult

输出如下所示。The output is as follows.

(1, 34) (2, 33) (0, 33)

前面的输出显示,原始序列中有34个元素,这些元素生成了键1,33值生成了键2,并显示了生成密钥0的33值。The previous output shows that there were 34 elements of the original sequence that produced the key 1, 33 values that produced the key 2, and 33 values that produced the key 0.

可以通过调用序列 groupBy对序列中的元素进行分组。You can group elements of a sequence by calling Seq.groupBy. Seq.groupBy 采用一个序列和一个从元素生成键的函数。Seq.groupBy takes a sequence and a function that generates a key from an element. 函数在序列的每个元素上执行。The function is executed on each element of the sequence. Seq.groupBy 返回一个元组序列,其中每个元组的第一个元素是键,第二个元素是生成该键的元素的序列。Seq.groupBy returns a sequence of tuples, where the first element of each tuple is the key and the second is a sequence of elements that produce that key.

下面的代码示例演示 Seq.groupBy 如何使用将编号从1到100的序列分为三个组,这些组具有非重复键值0、1和2。The following code example shows the use of Seq.groupBy to partition the sequence of numbers from 1 to 100 into three groups that have the distinct key values 0, 1, and 2.

let sequence = seq { 1 .. 100 }

let printSeq seq1 = Seq.iter (printf "%A ") seq1

let sequences3 =
    sequences
    |> Seq.groupBy (fun index ->
        if (index % 3 = 0) then 0
        elif (index % 3 = 1) then 1
        else 2)

sequences3 |> printSeq

输出如下所示。The output is as follows.

(1, seq [1; 4; 7; 10; ...]) (2, seq [2; 5; 8; 11; ...]) (0, seq [3; 6; 9; 12; ...])

通过调用 Seq,可以创建一个消除重复元素的序列You can create a sequence that eliminates duplicate elements by calling Seq.distinct. 或者,可以使用 seq.distinctby,它采用在每个元素上调用的键生成函数。Or you can use Seq.distinctBy, which takes a key-generating function to be called on each element. 生成的序列包含具有唯一键的原始序列的元素;随后将丢弃向早期元素生成重复键的元素。The resulting sequence contains elements of the original sequence that have unique keys; later elements that produce a duplicate key to an earlier element are discarded.

下面的代码示例阐释了的用法 Seq.distinctThe following code example illustrates the use of Seq.distinct. Seq.distinct 通过生成表示二进制数字的序列,并显示唯一不同的元素是0和1来演示。Seq.distinct is demonstrated by generating sequences that represent binary numbers, and then showing that the only distinct elements are 0 and 1.

let binary n =
    let rec generateBinary n =
        if (n / 2 = 0) then [n]
        else (n % 2) :: generateBinary (n / 2)

    generateBinary n
    |> List.rev
    |> Seq.ofList

printfn "%A" (binary 1024)

let resultSequence = Seq.distinct (binary 1024)
printfn "%A" resultSequence

下面的代码演示了 Seq.distinctBy 一个序列,该序列包含负数和正数,并使用绝对值函数作为键生成函数。The following code demonstrates Seq.distinctBy by starting with a sequence that contains negative and positive numbers and using the absolute value function as the key-generating function. 生成的序列缺少与序列中的负数相对应的所有正数,因为负数出现在序列的前面,因此选择了,而不是具有相同绝对值或键的正数。The resulting sequence is missing all the positive numbers that correspond to the negative numbers in the sequence, because the negative numbers appear earlier in the sequence and therefore are selected instead of the positive numbers that have the same absolute value, or key.

let inputSequence = { -5 .. 10 }
let printSeq seq1 = Seq.iter (printf "%A ") seq1

printfn "Original sequence: "
printSeq inputSequence

printfn "\nSequence with distinct absolute values: "
let seqDistinctAbsoluteValue = Seq.distinctBy (fun elem -> abs elem) inputSequence
printSeq seqDistinctAbsoluteValue

Readonly 和缓存序列Readonly and Cached Sequences

Seq readonly 创建序列的只读副本。Seq.readonly creates a read-only copy of a sequence. Seq.readonly 当你具有读写集合(如数组),并且你不希望修改原始集合时,此方法非常有用。Seq.readonly is useful when you have a read-write collection, such as an array, and you do not want to modify the original collection. 此函数可用于保留数据封装。This function can be used to preserve data encapsulation. 在下面的代码示例中,创建了一个包含数组的类型。In the following code example, a type that contains an array is created. 属性将公开数组,但不返回数组,而是返回从数组使用创建的序列 Seq.readonlyA property exposes the array, but instead of returning an array, it returns a sequence that is created from the array by using Seq.readonly.

type ArrayContainer(start, finish) =
    let internalArray = [| start .. finish |]
    member this.RangeSeq = Seq.readonly internalArray
    member this.RangeArray = internalArray

let newArray = new ArrayContainer(1, 10)
let rangeSeq = newArray.RangeSeq
let rangeArray = newArray.RangeArray
// These lines produce an error:
//let myArray = rangeSeq :> int array
//myArray.[0] <- 0
// The following line does not produce an error.
// It does not preserve encapsulation.
rangeArray.[0] <- 0

Seq: 创建序列的存储版本。Seq.cache creates a stored version of a sequence. 使用 Seq.cache 可以避免重新计算序列,或者当你有多个使用序列的线程时,但必须确保每个元素仅被处理一次。Use Seq.cache to avoid reevaluation of a sequence, or when you have multiple threads that use a sequence, but you must make sure that each element is acted upon only one time. 如果有多个线程正在使用的序列,则可以让一个线程枚举并计算原始序列的值,其余线程可以使用缓存的序列。When you have a sequence that is being used by multiple threads, you can have one thread that enumerates and computes the values for the original sequence, and remaining threads can use the cached sequence.

对序列执行计算Performing Computations on Sequences

简单的算术运算类似于列表的操作,如 seq、seq、 sumaverageBysumBy等。Simple arithmetic operations are like those of lists, such as Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, and so on.

序列摺seq、化简seq。扫描 类似于列表可用的对应函数。Seq.fold, Seq.reduce, and Seq.scan are like the corresponding functions that are available for lists. 序列支持列出支持的这些功能的一部分完全不同。Sequences support a subset of the full variations of these functions that lists support. 有关详细信息和示例,请参阅 列表For more information and examples, see Lists.

另请参阅See also