Sekvence (F#)

A sekvence je řada logické prvky jednoho typu.Posloupnosti jsou zvláště užitečné, když máte velký, objednané kolekce dat, ale nebudou muset použít všechny prvky.Jednotlivé prvky jsou počítány pouze jako posloupnost povinné, takže posloupnost může poskytnout lepší výkon než v situacích, ve kterých jsou použity všechny prvky seznamu.Číselné řady jsou zastoupeny seq<'T> typ, který je alias pro IEnumerable<T>.Proto libovolný.NET Framework typu, který implementuje System.IEnumerable lze použít jako sekvenci.Modulu Seq poskytuje podporu pro manipulaci, zahrnující sekvence.

Řada výrazů

A výraz sekvence je výraz, který je vyhodnocen jako posloupnost.Sekvence výrazů může trvat několik formulářů.Nejjednodušší podobě určuje rozsah.Například seq { 1 .. 5 } vytvoří posloupnost, která obsahuje pět prvků včetně koncových bodů 1 a 5.Můžete také určit přírůstek (nebo snížit) mezi dvěma obdobími double.Následující kód například vytvoří posloupnost násobkem 10.

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

Řada výrazů jsou tvořeny F# výrazy, které vracet hodnoty sekvenci.Mohou použít yield klíčové hodnoty, které se stanou součástí posloupnosti vyrábět.

Následuje příklad.

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

Můžete použít -> namísto operátoru yield, v tom případě můžete vynechat do klíčové slovo, jak ukazuje následující příklad.

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

Následující kód vygeneruje seznam dvojice souřadnic spolu s index do pole, které představuje mřížky.

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

if Výraz použitý v posloupnosti je filtr.Například generovat posloupnost pouze prvočísel za předpokladu, že mají funkci isprime typu int -> bool, takto vytvořit sekvenci.

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

Při použití yield nebo -> v iteraci, očekává každé opakování generovat prvek sekvence.Pokud každé opakování vytvoří posloupnost prvků, použijte yield!.V takovém případě jsou prvky, které jsou generovány při každém opakování zřetězeny vyrábět konečné pořadí.

Můžete kombinovat více výrazů společně v výraz sekvence.Prvky generovaných každý výraz spojeny dohromady.Příklad naleznete v části "Příklady" tohoto tématu.

Příklady

První příklad používá výraz sekvence, která obsahuje iteraci, filtru a výnos generovat pole.Tento kód Vytiskne posloupnost prvočísel mezi 1 a 100 do konzoly.

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

Následující kód používá yield k vytvoření tabulky násobení skládající se z n-tic tří prvků každé dva faktory a produktu.

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

Následující příklad ukazuje použití yield! sloučit do jediného konečného pořadí jednotlivých sekvencí.V tomto případě sekvencí pro každý dílčí stromová struktura v binární strom jsou zřetězeny rekurzivní funkce vyrábět konečné pořadí.

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

Pomocí sekvence

Sekvence podporuje mnoho funkcí, seznam.Sekvence také podporovat operace, například seskupení a počítání pomocí funkcí generování klíče.Sekvence také podpora více různých funkcí extrahování dílčích sekvencí.

Různé typy dat, například seznamů, polí, sady a mapy jsou implicitně sekvencí, protože jsou agregující kolekcí.Funkce, která trvá posloupnost jako argument funguje všechny běžné F# datové typy, vedle.NET Framework datový typ, který implementuje IEnumerable<T>.Kontrast tato funkce, která používá seznam jako argument, který lze převzít pouze seznamy.Typ seq<'a> je typ zkratka pro IEnumerable<'a>.To znamená, že jakýkoli typ, který implementuje obecného IEnumerable<T>, která obsahuje pole, seznamy, nastaví a mapuje v F# a také většinu.NET Framework, typy kolekcí, je kompatibilní s seq zadejte a může být použit kdykoli posloupnost očekává.

Funkce modulu

Modulu Seq v oboru názvů Microsoft.FSharp.Collections obsahuje funkce pro práci s sekvence.Tyto funkce pracovat seznamů, polí, mapy a sad, protože všechny tyto typy vyčíslitelné a proto lze považovat sekvence.

Vytváření sekvencí

Sekvence můžete vytvořit pomocí sekvence výrazů výše popsaným způsobem nebo pomocí určitých funkcí.

Můžete vytvořit prázdný posloupnosti pomocí Seq.empty, nebo můžete vytvořit pouze jeden prvek zadané posloupnosti pomocí Seq.singleton.

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

Můžete použít Seq.init pro vytvoření posloupnosti, jehož prvky jsou vytvořeny pomocí funkce, které zadáte.Také poskytují velikost posloupnosti.Tato funkce je stejně jako List.init, až na to, že prvky nebudou vytvořeny, dokud iterovat sekvence.Následující kód ilustruje použití Seq.init.

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

Výstup je

0 10 20 30 40

Pomocí Seq.ofArray a SEQ.ofList, <'T> Funkce (F#), můžete vytvořit číselné řady z pole a seznamy.Však můžete také převést pole a seznamy sekvence pomocí operátoru přetypování.Obě tyto metody jsou uvedeny v následujícím kódu.

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

Pomocí Seq.cast, můžete vytvořit sekvenci z kolekce slabě zadaný jako jsou vymezeny v System.Collections.Takové slabě zadané kolekce mají typ prvku Object a budou vyčísleny pomocí jiného než obecného IEnumerable<T> typu.Následující kód ilustruje použití Seq.cast převést ArrayList do sekvence.

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

Nekonečné posloupnosti lze definovat pomocí Seq.initInfinite funkce.Sekvence poskytnete funkce, která vytváří každý prvek z index prvku.Nekonečné posloupnosti jsou možné z důvodu opožděné hodnocení; prvky jsou vytvořeny podle potřeby voláním funkce, které zadáte.Následující příklad kódu vytváří nekonečnou sérii čísly s pohyblivou desetinnou, v tomto případě střídání řada kladných čtverce po sobě jdoucí celá čísla.

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 generuje sekvenci z výpočtu funkci, která má stav a převede jej vyrábět každý následující prvek v pořadí.Je to pouze hodnota, která slouží k výpočtu jednotlivých prvků a změnit každý prvek je vypočítávána.Druhý argument na Seq.unfold je počáteční hodnota, která se používá ke spuštění sekvence.Seq.unfoldpoužívá typ možnosti pro stát umožňuje ukončit posloupnost vracející None hodnotu.Následující kód ukazuje dva příklady sekvencí, seq1 a fib, které jsou generovány unfold operace.První, seq1, je stejně jednoduché posloupnosti s čísla až do 100.Druhý, fib, používá unfold sekvence Fibonacci vypočítat.Každý prvek v pořadí Fibonacci je součtem předchozí dvě čísla Fibonacci, stát hodnotu n-tice, který se skládá z předchozí dvě čísla v pořadí.Počáteční hodnota je (1,1), první dvě čísla v pořadí.

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

Výstup je následující:

Seq1 sekvence obsahuje čísla od 0 do 20.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Fib sekvence obsahuje Fibonacci čísla.

2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

Následující kód je příklad, který používá mnoho funkcí modulu sekvence popsané zde generovat a výpočtu hodnot nekonečné posloupnosti.Kód může trvat několik minut.

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

Hledání a hledání prvky

Sekvence podporují funkce, které jsou k dispozici seznamy: Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind, a Seq.tryFindIndex.Verze těchto funkcí, které jsou k dispozici pro sekvence vyhodnotit sekvence pouze na prvek, který je vyhledáván.Příklady naleznete v tématu seznam.

Získání dílčích sekvencí

SEQ.Filter a Seq.choose jsou jako odpovídající funkce, které jsou k dispozici pro seznamy, filtrování a výběr nedojde, dokud jsou vyhodnocovány v pořadí prvků.

SEQ.truncate z jiného sekvence vytvoří posloupnost, ale omezuje sekvence pro zadaný počet prvků.SEQ.take vytvoří nové sekvence obsahující zadaný počet prvků od začátku posloupnosti.Pokud existují méně elementů v pořadí, než zadáte přijmout, Seq.take vyvolá InvalidOperationException.Rozdíl mezi Seq.take a Seq.truncate je Seq.truncate nevytvářejí chybu, pokud zadáte číslo menší než počet prvků.

Následující kód ukazuje chování a rozdíly mezi Seq.truncate a 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

Výstup, než dojde k chybě, je takto.

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

Pomocí Seq.takeWhile, můžete zadat funkci predikátu (logické funkce) a vytvoření sekvence z jiného sekvence, které se skládá z těchto prvků původní posloupnost, pro které je predikátu true, ale zastavit před první prvek, pro který predikátu vrátí false.SEQ.Skip vrátí sekvence, které přeskočí zadaný počet první prvky jiného pořadí a vrací zbývající prvky.SEQ.skipWhile Vrátí pořadí, které přeskočí první prvky jiného pořadí predikátu vrátí jako truea potom vrátí zbývající prvky, počínaje první prvek, pro který predikátu vrátí false.

Následující příklad kódu ukazuje chování a rozdíly mezi Seq.takeWhile, Seq.skip, a 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

Výstup je takto.

1 4 9 
36 49 64 81 100 
16 25 36 49 64 81 100 

Transformace sekvence

SEQ.Pairwise vytvoří nové sekvence seskupený následné prvky vstupní sekvence do n-tic.

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 jako Seq.pairwise, až na to, že namísto vyrábějící posloupnost n-tic vyrábí pořadí polí, které obsahují kopie sousedící prvky ( okno) z číselné řady.Každé pole zadáte číslo sousedící prvky, které chcete.

Následující příklad kódu ukazuje použití Seq.windowed.V tomto případě je počet prvků v okně 3.V příkladu je printSeq, která je definována v předchozím příkladu kódu.

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

Výstup je takto.

Počáteční sekvence:

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

Operace s více sekvencí

SEQ.zip a Seq.zip3 trvat dvou nebo tří řad a vytvoření sekvence n-tic.Tyto funkce jsou jako odpovídající funkce, které jsou k dispozici pro seznam.Není k dispozici žádná odpovídající funkce oddělit jednu řadu do dvou nebo více řad.Potřebujete-li tuto funkci pro posloupnost pořadí převést na seznam a použít List.unzip.

Řazení, porovnání a seskupení

Řazení funkce podporované pro seznamy pracovat také s sekvence.To zahrnuje Seq.sort a Seq.sortBy.Tyto funkce iterovat celá řada.

Porovnat dvě sekvence pomocí Seq.compareWith funkce.Funkce porovnává postupně po sobě následujících prvků a zastaví, když narazí na první pár nerovností.Další prvky nepřispívají k porovnání.

Následující kód ukazuje použití 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.")

V předchozím kódu je první prvek vypočítanou a vyšetří a výsledek je -1.

SEQ.countBy funkce, která vytváří hodnotu s názvem trvá klíč pro každý prvek.Klíč vytváří pro každý prvek volání této funkce na každý prvek.Seq.countByVrátí pořadí, které obsahuje hodnoty klíče a spočítat počet prvků, které jsou generovány každou hodnotu klíče.

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

Výstup je takto.

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

Předchozí výstup ukazuje, že byly 34 prvky původní pořadí, které produkují klíč 1, 33 hodnoty, které produkují klíč 2 a 33 hodnoty, které produkují klíč 0.

Můžete seskupit prvky posloupnosti voláním Seq.groupBy.Seq.groupBytrvá posloupnost a funkci, která vygeneruje klíč z elementu.Funkce je provedena na každý prvek sekvence.Seq.groupByVrátí pořadí n-tic, kde první prvek každého záznamu je klíč a druhý je posloupnost prvků, které vytvoří klíč.

Následující příklad kódu ukazuje použití Seq.groupBy oddíl posloupnost čísel od 1 do 100 do tří skupin, které mají odlišné klíč hodnoty 0, 1 a 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

Výstup je takto.

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

Můžete vytvořit sekvenci, který odstraňuje duplicitní prvky voláním Seq.distinct.Nebo můžete použít Seq.distinctBy, který trvá generování klíče funkci volat pro každý prvek.Výsledné pořadí obsahuje původní posloupnost prvků, které mají jedinečné klíče; vyšší prvky, které vytvoří duplicitní klíč starší prvku jsou zahozeny.

Následující příklad kódu ukazuje použití Seq.distinct.Seq.distinctje prokázána generováním sekvence, které představují binární čísla a potom ukazující, že pouze rozdílné prvky jsou 0 a 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

Následující kód ukazuje Seq.distinctBy počínaje sekvence, který obsahuje čísla negativní a pozitivní a pomocí funkce absolutní hodnotu jako funkci generování klíče.Výsledné pořadí chybí kladná čísla, které odpovídají záporná čísla v pořadí, protože dříve v pořadí záporná čísla a proto jsou vybrány namísto kladná čísla, která mají stejné absolutní hodnota nebo klíč.

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

Jen pro čtení a mezipaměti sekvence

SEQ.ReadOnly vytvoří kopii jen pro čtení sekvence.Seq.readonlyje užitečné, když máte kolekci pro čtení a zápis, například pole, a nechcete měnit původní kolekce.Tato funkce slouží k zapouzdření dat zachovat.Následující příklad kódu je vytvořen typ, který obsahuje pole.Zpřístupní vlastnosti pole, ale nevrací matice vrátí vytvořené z matice pomocí sekvence 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 vytvoří posloupnost uložené verzi.Použít Seq.cache zabránit nové vyhodnocení sekvence nebo pokud máte více podprocesů, které využívají sekvenci, ale musíte přesvědčit, že každý prvek je rozhodnuto pouze jednou.Máte sekvence, který je používán více podprocesů, může mít jeden podproces, který vytvoří výčet a vypočítá hodnoty pro původní posloupnost a zbývající vlákna pomocí sekvence v mezipaměti.

Provádění výpočty v posloupnosti

Jednoduché aritmetické operace jsou například seznamy, například Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, atd.

SEQ.fold, Seq.reduce, a Seq.scan jsou jako odpovídající funkce, které jsou k dispozici pro seznamy.Sekvence podporují podmnožinu úplné variace těchto funkcí obsahuje podporu.Další informace a příklady naleznete v tématu Seznamy (F#).

Viz také

Referenční dokumentace

IEnumerable<T>

Další zdroje

F# Language Reference

Typy F#