# 序列Sequences

## 順序運算式Sequence Expressions

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


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


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


let (height, width) = (10, 10)
seq { for row in 0 .. width - 1 do
for col in 0 .. height - 1 do
yield (row, col, row*width + col)
}


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


## 範例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 yield n }
for x in aSequence do
printfn "%d" x


let multiplicationTable =
seq { for i in 1..9 do
for j in 1..9 do
yield (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 Microsoft.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 mutable arrayList1 = new System.Collections.ArrayList(10)
for i in 1 .. 10 do arrayList1.Add(10) |> ignore
let seqCast : seq<int> = Seq.cast arrayList1


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.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使用狀態的選項類型, 可讓您藉由None傳回值來終止序列。Seq.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. 由於每個數列序列中的元素都是前兩個斐報數位的總和, 因此 state 值是由序列中前兩個數字組成的元組。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 = Seq.unfold (fun state -> if (state > 20) then None else Some(state, state + 1)) 0
printfn "The sequence seq1 contains numbers from 0 to 20."
for x in seq1 do printf "%d " x
let fib = Seq.unfold (fun state ->
if (snd state > 1000) then None
else Some(fst state + snd state, (snd state, fst state + snd state))) (1,1)
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


// infiniteSequences.fs
// 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 series is the series of reciprocals of whole numbers.
let harmonicSeries = generateInfiniteSequence (fun index -> float index) false
// 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 =
Seq.unfold (fun state ->
let subtotal = snd state + Seq.nth (fst state + 1) sequence
if (fst state >= length) then None
else Some(subtotal,(fst state + 1, subtotal))) (0, 0.0)

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


## 搜尋和尋找元素Searching and Finding Elements

Sequences 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。選擇與可用於清單的對應函式相似, 不同之處在于在評估序列元素之前, 不會進行篩選和選擇。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.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.InvalidOperationException會擲回。If there are fewer elements in the sequence than you specify to take, Seq.take throws a System.InvalidOperationException. Seq.take Seq.truncate之間的差異在於, 如果元素數目少於您指定的數目, 就不會產生錯誤。 Seq.truncateThe 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

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


Seq.countby接受一個函式, 此函式會針對每個專案產生稱為索引的值。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; printfn ""
let seqResult = Seq.countBy (fun elem -> if elem % 3 = 0 then 0
elif elem % 3 = 1 then 1
else 2) mySeq1

printSeq seqResult


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


let sequence = seq { 1 .. 100 }
let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""
let sequences3 = Seq.groupBy (fun index ->
if (index % 3 = 0) then 0
elif (index % 3 = 1) then 1
else 2) sequence
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 ""
printfn "Original sequence: "
printSeq inputSequence
printfn "\nSequence with distinct absolute values: "
let seqDistinctAbsoluteValue = Seq.distinctBy (fun elem -> abs elem) inputSequence
seqDistinctAbsoluteValue |> printSeq


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.readonly所建立的序列。A 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
// The following line does not produce an error.
// It does not preserve encapsulation.
rangeArray. <- 0


Seq. cache會建立序列的預存版本。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] 和 [seq]。 scan就像是可用於清單的對應函數。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.