シーケンスSequences

シーケンスは、すべて1つの型からなる論理的な一連の要素です。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を含む5つの要素を含むシーケンスを作成します。For example, seq { 1 .. 5 } creates a sequence that contains five elements, including the endpoints 1 and 5. 2つの2つの期間の間にインクリメント (またはデクリメント) を指定することもできます。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 yield ます。Alternatively, 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 if ます。As 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}
}

を考えるもう1つの方法は、内部シーケンスを平坦化し、 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 からまでのすべての値に加えて、の値が生成され 1 x x ます。The 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

次の例では、3つの要素の組で構成される乗算テーブルを作成します。各要素は2つの要素と製品で構成されています。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! 個々のシーケンスを1つの最終シーケンスに結合する方法を示します。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.

空のシーケンスは、 seqを使用して作成できます。また、 seq. シングルトンを使用して、指定した要素のシーケンスを1つだけ作成することもできます。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.init の使用例です。The 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

Seq. ofArraySeq. Ofarray< t> 関数を使用すると、配列とリストからシーケンスを作成できます。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. castを使用すると、で定義されているような、弱く型指定されたコレクションからシーケンスを作成できます 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;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 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. 次のコード例では、浮動小数点数の無限のシーケンスが生成されます。この例では、連続した整数の2乗の 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. の2番目の引数 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 操作によって生成されるシーケンス (と) の2つの例を示して unfold います。The following code shows two examples of sequences, seq1 and fib, that are generated by an unfold operation. 1つ目のは、 seq1 数が20までの単純なシーケンスです。The first, seq1, is just a simple sequence with numbers up to 20. 2番目のは、を fib 使用し unfold てフィボナッチシーケンスを計算します。The second, fib, uses unfold to compute the Fibonacci sequence. フィボナッチシーケンス内の各要素は前の2つのフィボナッチ数の合計であるため、状態の値は、シーケンス内の前の2つの数値で構成される組になります。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) 、シーケンスの最初の2つの数値です。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

シーケンスは、リストで使用できる機能をサポートし ていますlist.exists2seq、Seq、seq。 findindex 、Seq. tryfind、および 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. truncate は、別のシーケンスからシーケンスを作成しますが、シーケンスは指定した数の要素に制限されます。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.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.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

Seqを使用することにより、述語関数 (ブール関数) を指定し、述語が返される元のシーケンスの要素で構成される別のシーケンスからシーケンスを作成でき true ます。ただし、述語が返す最初の要素の前には停止し false ます。By 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. Seq. 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

Seq.zipSeq.zip3 は、2つまたは3つのシーケンスを受け取り、組のシーケンスを生成します。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. 1つのシーケンスを2つ以上のシーケンスに分割する対応する機能はありません。There is no corresponding functionality to separate one sequence into two or more sequences. シーケンスにこの機能が必要な場合は、シーケンスをリストに変換し、 unzipを使用します。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. これに は、 SortBy および seqが含まれます。This includes Seq.sort and Seq.sortBy. これらの関数は、シーケンス全体を反復処理します。These functions iterate through the whole sequence.

2つのシーケンスを比較するには、 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 は、各要素の キー と呼ばれる値を生成する関数を受け取ります。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)

前の出力は、キー1、キー2を生成した33値、およびキー0を生成した33値を生成した、元のシーケンスの34要素があることを示しています。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 組のシーケンスを返します。各組の最初の要素はキーで、2番目の要素はそのキーを生成する要素のシーケンスです。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 0、1、および2の個別のキー値を持つ3つのグループに、1 ~ 100 の一連の数値を分割しています。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.distinct の使用方法を次のコード例に示します。The 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 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シーケンスの再評価を避けるため、またはシーケンスを使用する複数のスレッドがある場合は、を使用して、各要素が1回だけ動作するようにする必要があります。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. 複数のスレッドで使用されているシーケンスがある場合は、元のシーケンスの値を列挙して計算するスレッドを1つ持つことができ、残りのスレッドはキャッシュされたシーケンスを使用できます。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. average、seq. sum、seq. AverageByseq. sumbyなどのリストのようなものです。Simple arithmetic operations are like those of lists, such as Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, and so on.

SeqSeq、および 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