시퀀스

시퀀스는 한 형식의 모든 요소의 논리적 계열입니다. 시퀀스는 정렬된 큰 데이터 컬렉션이 있지만 모든 요소를 반드시 사용할 필요는 없는 경우에 특히 유용합니다. 개별 시퀀스 요소는 필요에 따라 계산되므로 시퀀스는 모든 요소가 사용되지 않는 경우 목록보다 더 나은 성능을 제공할 수 있습니다. 시퀀스는 형식으로 seq<'T> 표현되며, 이는 에 대한 IEnumerable<T>별칭입니다. 따라서 인터페이스를 구현하는 모든 .NET 형식을 IEnumerable<T> 시퀀스로 사용할 수 있습니다. Seq 모듈시퀀스를 포함하는 조작을 지원합니다.

시퀀스 식

시퀀스 식은 시퀀스로 계산되는 식입니다. 시퀀스 식은 여러 가지 형식을 사용할 수 있습니다. 가장 간단한 폼은 범위를 지정합니다. 예를 들어 엔드 seq { 1 .. 5 } 포인트 1과 5를 포함하여 5개의 요소가 포함된 시퀀스를 만듭니다. 두 기간 사이의 증가(또는 감소)를 지정할 수도 있습니다. 예를 들어 다음 코드는 10의 배수 시퀀스를 만듭니다.

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

시퀀스 식은 시퀀스의 값을 생성하는 F# 식으로 구성됩니다. 프로그래밍 방식으로 값을 생성할 수도 있습니다.

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

이전 샘플에서는 연산자를 -> 사용하여 값이 시퀀스의 일부가 될 식을 지정할 수 있습니다. 뒤에 있는 코드의 모든 부분이 값을 반환하는 경우에만 사용할 -> 수 있습니다.

또는 다음과 같은 선택 사항 yield 으로 키워드(keyword) 지정할 do 수 있습니다.

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
}

다음 코드는 그리드를 나타내는 배열에 인덱스와 함께 좌표 쌍 목록을 생성합니다. 첫 번째 for 식은 do 지정해야 합니다.

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 시퀀스에 사용되는 식은 필터입니다. 예를 들어 형식의 함수 isprimeint -> bool가 있다고 가정하고 소수만 시퀀스를 생성하려면 다음과 같이 시퀀스를 생성합니다.

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

앞에서 do 멘션 대로 여기서는 해당 분기와 함께 if사용하는 분기가 없 else 으므로 이때 필요합니다. 사용 ->하려고 하면 모든 분기가 값을 반환하지 않는다는 오류가 발생합니다.

yield! 키워드

경우에 따라 요소 시퀀스를 다른 시퀀스에 포함할 수 있습니다. 다른 시퀀스 내에 시퀀스를 포함하려면 키워드(keyword) 사용해야 yield! 합니다.

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

또 다른 사고 yield! 방법은 내부 시퀀스를 평면화한 다음 포함하는 시퀀스에 포함하는 것입니다.

식에서 사용되는 경우 yield! 다른 모든 단일 값은 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}
}

이전 예제에서는 각 값에 대한 모든 값 외에도 값을 x1 생성합니다x.x

예제

첫 번째 예제에서는 반복, 필터 및 수율을 포함하는 시퀀스 식을 사용하여 배열을 생성합니다. 이 코드는 1에서 100 사이의 소수 시퀀스를 콘솔에 출력합니다.

// 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! 보여 줍니다. 이 경우 이진 트리의 각 하위 트리에 대한 시퀀스가 재귀 함수에 연결되어 최종 시퀀스를 생성합니다.

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

시퀀스 사용

시퀀스는 목록과 동일한 많은 함수를 지원합니다. 또한 시퀀스는 키 생성 함수를 사용하여 그룹화 및 계산과 같은 작업을 지원합니다. 시퀀스는 하위 시퀀스를 추출하기 위한 보다 다양한 함수도 지원합니다.

목록, 배열, 집합 및 맵과 같은 많은 데이터 형식은 열거 가능한 컬렉션이므로 암시적으로 시퀀스입니다. 시퀀스를 인수로 사용하는 함수는 구현하는 모든 .NET 데이터 형식 외에도 공통 F# 데이터 형식에서 작동합니다 System.Collections.Generic.IEnumerable<'T>. 목록을 인수로 사용하는 함수와 대조합니다. 이 함수는 목록만 사용할 수 있습니다. 형식 seq<'T> 은 에 대한 IEnumerable<'T>형식 약어입니다. 즉, F#의 배열, 목록, 집합 및 맵을 포함하는 제네릭 System.Collections.Generic.IEnumerable<'T>을 구현하는 모든 형식과 대부분의 .NET 컬렉션 형식은 형식과 seq 호환되며 시퀀스가 필요한 곳마다 사용할 수 있습니다.

모듈 함수

FSharp.Collections 네임스페스의 Seq 모듈에는 시퀀스 작업을 위한 함수가 포함되어 있습니다. 이러한 함수는 목록, 배열, 맵 및 집합에서도 작동합니다. 이러한 형식은 모두 열거 가능하므로 시퀀스로 처리할 수 있기 때문입니다.

시퀀스 만들기

앞에서 설명한 대로 시퀀스 식을 사용하거나 특정 함수를 사용하여 시퀀스를 만들 수 있습니다.

Seq.empty를 사용하여 빈 시퀀스를 만들거나 Seq.singleton을 사용하여 지정된 요소 하나만 시퀀스를 만들 수 있습니다.

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

Seq.init를 사용하여 사용자가 제공하는 함수를 사용하여 요소가 만들어지는 시퀀스를 만들 수 있습니다. 시퀀스에 대한 크기도 제공합니다. 이 함수는 시퀀스를 반복할 때까지 요소가 만들어지지 않는다는 점을 제외하고 List.init와 같습니다. 다음 코드에서는 .의 Seq.init사용을 보여 줍니다.

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

출력은 다음과 같습니다.

0 10 20 30 40

Seq.ofArray 및 Seq.ofList'T<> 함수를 사용하여 배열 및 목록에서 시퀀스를 만들 수 있습니다. 그러나 캐스트 연산자를 사용하여 배열 및 목록을 시퀀스로 변환할 수도 있습니다. 두 기술 모두 다음 코드에 나와 있습니다.

// 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.Collections. 이러한 약한 형식의 컬렉션은 요소 형식 System.Object 을 가지며 제네릭 System.Collections.Generic.IEnumerable&#96;1 이 아닌 형식을 사용하여 열거됩니다. 다음 코드에서는 시퀀스로 변환 System.Collections.ArrayList 하는 데 사용하는 Seq.cast 방법을 보여 줍니다.

open System

let arr = ResizeArray<int>(10)

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

let seqCast = Seq.cast arr

Seq.initInfinite 함수를 사용하여 무한 시퀀스를 정의할 수 있습니다. 이러한 시퀀스의 경우 요소의 인덱스에서 각 요소를 생성하는 함수를 제공합니다. 지연 평가로 인해 무한 시퀀스가 가능합니다. 지정한 함수를 호출하여 필요에 따라 요소를 만듭니다. 다음 코드 예제에서는 부동 소수점 숫자의 무한 시퀀스를 생성합니다. 이 경우 연속 정수의 제곱이 번갈아 일련의 역수입니다.

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 는 상태를 사용하고 시퀀스의 각 후속 요소를 생성하도록 변환하는 계산 함수에서 시퀀스를 생성합니다. 상태는 각 요소를 계산하는 데 사용되는 값일 뿐이며 각 요소가 계산될 때 변경될 수 있습니다. 두 번째 인수 Seq.unfold 는 시퀀스를 시작하는 데 사용되는 초기 값입니다. Seq.unfold 는 값을 반환하여 시퀀스를 종료할 수 있는 상태에 대한 옵션 형식을 None 사용합니다. 다음 코드에서는 작업에 의해 unfold 생성되는 시퀀스와 시퀀스의 seq1fib두 가지 예를 보여 줍니다. 첫 번째 시 seq1퀀스는 최대 20개의 숫자가 있는 간단한 시퀀스입니다. 두 번째 , fib피보나치 시퀀스를 계산하는 데 사용합니다 unfold . 피보나치 시퀀스의 각 요소는 이전 두 피보나치 숫자의 합계이므로 상태 값은 시퀀스의 이전 두 숫자로 구성된 튜플입니다. 초기 값은 (0,1)시퀀스의 처음 두 숫자입니다.

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 =
    (0, 1)
    |> Seq.unfold (fun state ->
        let cur, next = state
        if cur < 0 then  // overflow
            None
        else
            let next' = cur + next
            let state' = next, next'
            Some (cur, 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.

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 

다음 코드는 여기에 설명된 많은 시퀀스 모듈 함수를 사용하여 무한 시퀀스의 값을 생성하고 계산하는 예제입니다. 코드를 실행하는 데 몇 분 정도 걸릴 수 있습니다.

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

요소 검색 및 찾기

시퀀스는 Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind 및 Seq.tryFindIndex함께 사용할 수 있는 기능을 지원합니다. 시퀀스에 사용할 수 있는 이러한 함수 버전은 검색되는 요소까지만 시퀀스를 평가합니다. 예제는 목록을 참조 하세요.

하위 시퀀스 가져오기

Seq.filterSeq.choose 은 시퀀스 요소가 평가될 때까지 필터링 및 선택되지 않는다는 점을 제외하고 목록에 사용할 수 있는 해당 함수와 같습니다.

Seq.truncate 는 다른 시퀀스에서 시퀀스를 만들지만 시퀀스를 지정된 수의 요소로 제한합니다. Seq.take 는 시퀀스 시작부터 지정된 수의 요소만 포함하는 새 시퀀스를 만듭니다. 시퀀스에 지정 Seq.takeSystem.InvalidOperationException한 것보다 적은 요소가 있으면 . Seq.take 요소 수가 지정한 Seq.truncate 수보다 작으면 오류가 발생하지 않는다는 점과 Seq.truncate 차이점이 있습니다.

다음 코드는 사이의 동작과 차이점을 보여 줍니다 Seq.truncateSeq.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

오류가 발생하기 전의 출력은 다음과 같습니다.

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.takeWhile을 사용하여 조건자 함수(부울 함수)를 지정하고 조건true자가 있는 원래 시퀀스의 요소로 구성된 다른 시퀀스에서 시퀀스를 만들 수 있지만 조건자가 반환되는 첫 번째 요소 앞에 중지할 수 있습니다false. Seq.skip은 다른 시퀀스의 첫 번째 요소 중 지정된 수를 건너뛰고 다시 기본 요소를 반환하는 시퀀스를 반환합니다. Seq.skipWhile는 조건자가 반환하는 한 다른 시퀀스의 첫 번째 요소를 건너뛰는 시퀀스를 반환한 다음 조건자가 반환true하는 첫 번째 요소부터 시작하여 다시 기본 요소를 반환합니다false.

다음 코드 예제에서는 , Seq.skipSeq.skipWhile. 사이의 동작과 차이점을 Seq.takeWhile보여 줍니다.

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

시퀀스 변환

Seq.pairwise 는 입력 시퀀스의 연속 요소가 튜플로 그룹화되는 새 시퀀스를 만듭니다.

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.windowed는 튜플 시퀀스를 생성하는 대신 시퀀스에서 인접한 요소()의 복사본을 포함하는 배열 시퀀스를 생성한다는 점을 제외하고 비슷합니다Seq.pairwise. 각 배열에서 원하는 인접 요소의 수를 지정합니다.

다음 코드 예제에서는 Seq.windowed의 사용법을 보여줍니다. 이 경우 창의 요소 수는 3입니다. 이 예제에서는 이전 코드 예제에 정의된 를 사용합니다 printSeq.

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

여러 시퀀스를 사용하는 작업

Seq.zip 및 Seq.zip3은 2~3개의 시퀀스를 사용하고 튜플 시퀀스를 생성합니다. 이러한 함수는 목록에 사용할 수 있는 해당 함수와 같습니다. 한 시퀀스를 둘 이상의 시퀀스로 구분하는 해당 기능은 없습니다. 시퀀스에 이 기능이 필요한 경우 시퀀스를 목록으로 변환하고 List.unzip을 사용합니다.

정렬, 비교 및 그룹화

목록에 지원되는 정렬 함수도 시퀀스에서 작동합니다. 여기에는 Seq.sort 및 Seq.sortBy가 포함됩니다. 이러한 함수는 전체 시퀀스를 반복합니다.

Seq.compareWith 함수를 사용하여 두 시퀀스를 비교합니다. 함수는 연속 요소를 차례로 비교하고 첫 번째 같지 않은 쌍이 발견되면 중지됩니다. 추가 요소는 비교에 기여하지 않습니다.

다음 코드는 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입니다.

Seq.countBy는 각 요소에 대한 키라는 값을 생성하는 함수를 사용합니다. 각 요소에서 이 함수를 호출하여 각 요소에 대해 키가 생성됩니다. Seq.countBy 그런 다음 키 값이 포함된 시퀀스와 키의 각 값을 생성한 요소 수의 수를 반환합니다.

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)

이전 출력은 키 1을 생성한 원래 시퀀스의 요소 34개, 키 2를 생성한 값 33개 및 키 0을 생성한 33개의 값이 있음을 보여줍니다.

Seq.groupBy를 호출하여 시퀀스의 요소를 그룹화할 수 있습니다. Seq.groupBy 는 요소에서 키를 생성하는 시퀀스 및 함수를 사용합니다. 이 함수는 시퀀스의 각 요소에서 실행됩니다. Seq.groupBy 는 각 튜플의 첫 번째 요소가 키이고 두 번째 요소는 해당 키를 생성하는 요소 시퀀스인 튜플 시퀀스를 반환합니다.

다음 코드 예제에서는 1에서 100까지의 숫자 시퀀스를 고유 키 값이 0, 1 및 2인 세 그룹으로 분할하는 방법을 Seq.groupBy 보여 줍니다.

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; ...])

Seq.distinct를 호출 하여 중복 요소를 제거하는 시퀀스를 만들 수 있습니다. 또는 각 요소에서 호출할 키 생성 함수를 사용하는 Seq.distinctBy를 사용할 수 있습니다. 결과 시퀀스에는 고유 키가 있는 원래 시퀀스의 요소가 포함됩니다. 이전 요소에 대한 중복 키를 생성하는 이후 요소는 dis카드ed입니다.

다음 코드 예제에서는 .의 Seq.distinct사용을 보여 줍니다. Seq.distinct 는 이진 번호를 나타내는 시퀀스를 생성한 다음 유일한 고유 요소가 0과 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 줍니다. 결과 시퀀스에는 시퀀스의 음수에 해당하는 모든 양수가 누락됩니다. 음수는 시퀀스의 앞부분에서 나타나므로 절대값 또는 키가 같은 양수 대신 선택되기 때문입니다.

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 는 배열과 같은 읽기-쓰기 컬렉션이 있고 원래 컬렉션을 수정하지 않으려는 경우에 유용합니다. 이 함수는 데이터 캡슐화를 유지하는 데 사용할 수 있습니다. 다음 코드 예제에서는 배열을 포함하는 형식이 만들어집니다. 속성은 배열을 노출하지만 배열을 반환하는 대신 배열을 사용하여 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 시퀀스의 재평가를 방지하거나 시퀀스를 사용하는 스레드가 여러 개 있지만 각 요소가 한 번만 작동하는지 확인해야 합니다. 여러 스레드에서 사용되는 시퀀스가 있는 경우 원래 시퀀스의 값을 열거하고 계산하는 하나의 스레드를 가질 수 있으며, 스레드를 다시 기본 캐시된 시퀀스를 사용할 수 있습니다.

시퀀스에서 계산 수행

간단한 산술 연산은 Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy 등과 같은 목록의 연산과 같습니다.

Seq.fold, Seq.reduce 및 Seq.scan은 목록에 사용할 수 있는 해당 함수와 같습니다. 시퀀스는 지원을 나열하는 이러한 함수의 전체 변형 하위 집합을 지원합니다. 자세한 내용 및 예제는 목록을 참조 하세요.

참고 항목