序列Sequences

注意

本文中的 API 參考連結將帶您前往 MSDN。The API reference links in this article will take you to MSDN. docs.microsoft.com API 參考不完整。The docs.microsoft.com API reference is not complete.

序列」是一種專案的邏輯數列, 全都屬於一個型別。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>型別表示, 這是的System.Collections.Generic.IEnumerable別名。Sequences are represented by the seq<'T> type, which is an alias for System.Collections.Generic.IEnumerable. 因此, 任何執行的System.IEnumerable .NET Framework 類型都可以當做序列使用。Therefore, any .NET Framework type that implements System.IEnumerable 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. 它們可以使用yield關鍵字來產生會成為序列一部分的值。They can use the yield keyword to produce values that become part of the sequence.

以下是範例。Following is an example.

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

您可以使用->運算子yield, 而不是, 在此do情況下, 您可以省略關鍵字, 如下列範例所示。You can use the -> operator instead of yield, in which case you can omit the do keyword, as shown in the following example.

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

下列程式碼會在代表方格的陣列中, 產生座標配對的清單, 以及一個索引。The following code generates a list of coordinate pairs along with an index into an array that represents the grid.

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

序列中使用的運算式是篩選準則。ifAn 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 yield n }

當您在yield反復->專案中使用或時, 每個反復專案都應該產生序列的單一元素。When you use yield or -> in an iteration, each iteration is expected to generate a single element of the sequence. 如果每個反復專案都會產生一系列的yield!專案, 請使用。If each iteration produces a sequence of elements, use yield!. 在此情況下, 會串連每個反復專案上產生的元素, 以產生最終的序列。In that case, the elements generated on each iteration are concatenated to produce the final sequence.

您可以在序列運算式中結合多個運算式。You can combine multiple expressions together in a sequence expression. 每個運算式所產生的元素會串連在一起。The elements generated by each expression are concatenated together. 如需範例, 請參閱本主題的「範例」一節。For an example, see the "Examples" section of this topic.

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

下列程式碼會yield使用來建立由三個元素的元組組成的乘法資料表, 每個專案都包含兩個因素和產品。The following code uses yield to create 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 do
               yield (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. 將序列當做引數使用的函式, 除了任何可執行檔F# .NET Framework 資料類型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 Framework 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 Framework 的集合型別) 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 Framework 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 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

如先前所述, 或使用特定函數, 您可以使用順序運算式來建立序列。You can create sequences by using sequence expressions, as described previously, or by using certain functions.

您可以使用 [ seq] 建立空的序列, 或使用 [ seq] 建立只有一個指定元素的序列。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], 建立使用您所提供的函式來建立元素的序列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. 不過, 您也可以使用 cast 運算子, 將陣列和清單轉換成序列。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.Collections定義的型別) 建立序列。By 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;1類型來列舉。Such 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 mutable arrayList1 = new System.Collections.ArrayList(10)
for i in 1 .. 10 do arrayList1.Add(10) |> ignore
let seqCast : seq<int> = Seq.cast arrayList1

您可以使用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.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 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.

// 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
    |> 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. existsseq. list.exists2seq. findseq. findIndexseq. picktryFindseq. array.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。選擇與可用於清單的對應函式相似, 不同之處在于在評估序列元素之前, 不會進行篩選和選擇。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.

下列程式碼顯示和Seq.truncate Seq.take之間的行為差異。The 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(只要述詞傳回), 然後傳回其餘的專案, 從該述詞傳回的第一個元素開始。 false.Seq.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.skipWhile和之間的行為和差異。The 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

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

清單支援的排序函數也適用于順序。The sorting functions supported for lists also work with sequences. 這包括seq. sortsortByThis 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.

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

輸出如下。The output is as follows.

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

先前的輸出顯示, 原始序列中有34個元素產生金鑰1、33值產生金鑰 2, 以及33產生金鑰0的值。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.

您可以藉由呼叫Seq. 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; printfn ""
let sequences3 = Seq.groupBy (fun index ->
                                if (index % 3 = 0) then 0
                                  elif (index % 3 = 1) then 1
                                  else 2) sequence
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. distinct來建立刪除重複元素的序列。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. 產生的序列遺漏了對應于序列中負數的所有正數, 因為負數會出現在序列中的前面, 因此會選取, 而不是具有相同絕對值的正數value 或 key。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 ""
printfn "Original sequence: "
printSeq inputSequence
printfn "\nSequence with distinct absolute values: "
let seqDistinctAbsoluteValue = Seq.distinctBy (fun elem -> abs elem) inputSequence
seqDistinctAbsoluteValue |> printSeq

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.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] <- 0
// The following line does not produce an error.
// It does not preserve encapsulation.
rangeArray.[0] <- 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. averageseq. sumaverageByseq. sumBy等等。Simple arithmetic operations are like those of lists, such as Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, and so on.

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

另請參閱See also