# 序列Sequences

## 序列表达式Sequence Expressions

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


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


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 }


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 }


## yield! 关键字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!在表达式中使用时，所有其他单个值必须使用 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}
}


## 示例Examples

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


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


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


## 模块函数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

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


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


0 10 20 30 40


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


open System

let arr = ResizeArray<int>(10)

for i in 1 .. 10 do

let seqCast = Seq.cast arr


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


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


## 获取个子序列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.

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


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


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.

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


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

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.")


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


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


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


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


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


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


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.