Delen via


Reeksen

Een reeks is een logische reeks elementen die allemaal van één type zijn. Reeksen zijn met name handig wanneer u een grote, geordende verzameling gegevens hebt, maar niet noodzakelijkerwijs alle elementen wilt gebruiken. Afzonderlijke reekselementen worden alleen als vereist berekend, zodat een reeks betere prestaties kan bieden dan een lijst in situaties waarin niet alle elementen worden gebruikt. Reeksen worden vertegenwoordigd door het seq<'T> type, een alias voor IEnumerable<T>. Daarom kan elk .NET-type dat interface implementeert IEnumerable<T> , worden gebruikt als een reeks. De Seq-module biedt ondersteuning voor manipulaties met behulp van reeksen.

Reeksexpressies

Een reeksexpressie is een expressie die resulteert in een reeks. Reeksexpressies kunnen een aantal vormen aannemen. In het eenvoudigste formulier wordt een bereik opgegeven. Hiermee maakt u bijvoorbeeld seq { 1 .. 5 } een reeks met vijf elementen, inclusief de eindpunten 1 en 5. U kunt ook een verhoging (of afschabbeling) tussen twee dubbele perioden opgeven. Met de volgende code wordt bijvoorbeeld de reeks veelvouden van 10 gemaakt.

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

Reeksexpressies bestaan uit F#-expressies die waarden van de reeks produceren. U kunt ook programmatisch waarden genereren:

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

In het vorige voorbeeld wordt de -> operator gebruikt, waarmee u een expressie kunt opgeven waarvan de waarde deel uitmaakt van de reeks. U kunt alleen gebruiken -> als elk deel van de code die volgt een waarde retourneert.

U kunt ook het do trefwoord opgeven, met een optioneel yield dat volgt:

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
}

Met de volgende code wordt een lijst met coördinaatparen samen met een index gegenereerd in een matrix die het raster vertegenwoordigt. Houd er rekening mee dat voor de eerste for expressie moet do worden opgegeven.

let (height, width) = (10, 10)

seq {
    for row in 0 .. width - 1 do
        for col in 0 .. height - 1 -> (row, col, row * width + col)
}

Een if expressie die in een reeks wordt gebruikt, is een filter. Als u bijvoorbeeld een reeks alleen priemgetallen wilt genereren, ervan uitgaande dat u een functie isprime van het type int -> boolhebt, maakt u de reeks als volgt.

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

Zoals eerder vermeld, do is hier vereist omdat er geen else vertakking bij de if. Als u probeert te gebruiken ->, krijgt u een foutmelding dat niet alle vertakkingen een waarde retourneren.

Het yield!-trefwoord

Soms wilt u mogelijk een reeks elementen opnemen in een andere reeks. Als u een reeks in een andere reeks wilt opnemen, moet u het yield! trefwoord gebruiken:

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

Een andere manier om te bedenken yield! is dat het een binnenste reeks plat maakt en dat vervolgens in de insluitingsvolgorde opneemt.

Wanneer yield! in een expressie wordt gebruikt, moeten alle andere enkelvoudige waarden het yield trefwoord gebruiken:

// Combine repeated values with their values
seq {
    for x in 1..10 do
        yield x
        yield! seq { for i in 1..x -> i}
}

In het vorige voorbeeld wordt de waarde van x naast alle waarden van 1 naar x elke xwaarde geproduceerd.

Voorbeelden

In het eerste voorbeeld wordt een reeksexpressie gebruikt die een iteratie, een filter en een opbrengst bevat om een matrix te genereren. Met deze code wordt een reeks priemgetallen tussen 1 en 100 naar de console afgedrukt.

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

In het volgende voorbeeld wordt een vermenigvuldigingstabel gemaakt die bestaat uit tuples van drie elementen, die elk bestaan uit twee factoren en het product:

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

In het volgende voorbeeld ziet u het gebruik van het combineren van yield! afzonderlijke reeksen in één laatste reeks. In dit geval worden de reeksen voor elke substructuur in een binaire boom samengevoegd in een recursieve functie om de uiteindelijke volgorde te produceren.

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

Reeksen gebruiken

Reeksen ondersteunen veel van dezelfde functies als lijsten. Reeksen ondersteunen ook bewerkingen zoals groeperen en tellen met behulp van functies die sleutel genereren. Reeksen ondersteunen ook diversere functies voor het extraheren van subsequences.

Veel gegevenstypen, zoals lijsten, matrices, sets en kaarten, zijn impliciet reeksen omdat ze inventariserbare verzamelingen zijn. Een functie die een reeks als argument gebruikt, werkt met een van de algemene F#-gegevenstypen, naast elk .NET-gegevenstype dat wordt geïmplementeerd System.Collections.Generic.IEnumerable<'T>. Vergelijk dit met een functie die een lijst als argument gebruikt, waardoor alleen lijsten kunnen worden gebruikt. Het type seq<'T> is een afkorting van het type voor IEnumerable<'T>. Dit betekent dat elk type dat het algemene System.Collections.Generic.IEnumerable<'T>implementeert, waaronder matrices, lijsten, sets en kaarten in F#, en ook de meeste .NET-verzamelingstypen, compatibel is met het seq type en kan worden gebruikt waar een reeks wordt verwacht.

Modulefuncties

De Seq-module in de naamruimte FSharp.Collections bevat functies voor het werken met reeksen. Deze functies werken ook met lijsten, matrices, kaarten en sets, omdat al deze typen kunnen worden opgesomd en daarom kunnen worden behandeld als reeksen.

Reeksen maken

U kunt reeksen maken met behulp van reeksexpressies, zoals eerder beschreven, of met behulp van bepaalde functies.

U kunt een lege reeks maken met behulp van Seq.empty of u kunt een reeks van slechts één opgegeven element maken met behulp van Seq.singleton.

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

U kunt Seq.init gebruiken om een reeks te maken waarvoor de elementen worden gemaakt met behulp van een functie die u opgeeft. U geeft ook een grootte op voor de reeks. Deze functie is net als List.init, behalve dat de elementen pas worden gemaakt als u de reeks doorloopt. De volgende code illustreert het gebruik van Seq.init.

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

De uitvoer is

0 10 20 30 40

Door Seq.ofArray en Seq.ofList'T>< Function te gebruiken, kunt u reeksen maken op basis van matrices en lijsten. U kunt echter ook matrices en lijsten converteren naar reeksen met behulp van een cast-operator. Beide technieken worden weergegeven in de volgende 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

Met Seq.cast kunt u een reeks maken op basis van een zwak getypte verzameling, zoals die zijn gedefinieerd in System.Collections. Dergelijke zwak getypte verzamelingen hebben het elementtype System.Object en worden opgesomd met behulp van het niet-generieke System.Collections.Generic.IEnumerable&#96;1 type. De volgende code illustreert het gebruik van het converteren van Seq.cast een System.Collections.ArrayList naar een reeks.

open System

let arr = ResizeArray<int>(10)

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

let seqCast = Seq.cast arr

U kunt oneindige reeksen definiëren met behulp van de functie Seq.initInfinite . Voor een dergelijke reeks geeft u een functie op waarmee elk element wordt gegenereerd op basis van de index van het element. Oneindige reeksen zijn mogelijk vanwege luie evaluatie; elementen worden indien nodig gemaakt door de functie aan te roepen die u opgeeft. In het volgende codevoorbeeld wordt een oneindige reeks drijvendekommanummers geproduceerd, in dit geval de afwisselende reeks wederzijdse waarden van kwadraten van opeenvolgende gehele getallen.

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 genereert een reeks van een rekenfunctie die een status neemt en deze transformeert om elk volgend element in de reeks te produceren. De status is slechts een waarde die wordt gebruikt om elk element te berekenen en kan veranderen wanneer elk element wordt berekend. Het tweede argument is Seq.unfold de initiële waarde die wordt gebruikt om de reeks te starten. Seq.unfold gebruikt een optietype voor de status, waarmee u de reeks kunt beëindigen door de None waarde te retourneren. De volgende code toont twee voorbeelden van reeksen en seq1fib, die worden gegenereerd door een unfold bewerking. De eerste, seq1is slechts een eenvoudige reeks met getallen tot 20. De tweede, fibwordt gebruikt unfold om de Fibonacci-reeks te berekenen. Omdat elk element in de Fibonacci-reeks de som is van de vorige twee Fibonacci-getallen, is de statuswaarde een tuple die uit de vorige twee getallen in de reeks bestaat. De initiële waarde is (0,1), de eerste twee getallen in de reeks.

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

De uitvoer is als volgt:

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 

De volgende code is een voorbeeld dat gebruikmaakt van veel van de functies van de reeksmodule die hier worden beschreven om de waarden van oneindige reeksen te genereren en te berekenen. Het uitvoeren van de code kan enkele minuten duren.

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

Elementen zoeken en zoeken

Reeksen ondersteunen functionaliteit die beschikbaar is met lijsten: Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind en Seq.tryFindIndex. De versies van deze functies die beschikbaar zijn voor reeksen evalueren de volgorde alleen tot het element waarnaar wordt gezocht. Zie Lijsten voor voorbeelden.

Subsequences verkrijgen

Seq.filter en Seq.choose zijn net als de bijbehorende functies die beschikbaar zijn voor lijsten, behalve dat het filteren en kiezen niet plaatsvindt totdat de reekselementen worden geëvalueerd.

Seq.truncate maakt een reeks van een andere reeks, maar beperkt de reeks tot een opgegeven aantal elementen. Seq.take maakt een nieuwe reeks die slechts een opgegeven aantal elementen bevat vanaf het begin van een reeks. Als de reeks minder elementen bevat dan u opgeeft, Seq.take genereert u een System.InvalidOperationException. Het verschil tussen Seq.take en Seq.truncate is dat Seq.truncate er geen fout optreedt als het aantal elementen kleiner is dan het getal dat u opgeeft.

De volgende code toont het gedrag van en verschillen tussen Seq.truncate en 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

De uitvoer, voordat de fout optreedt, is als volgt.

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

Met Seq.takeWhile kunt u een predicaatfunctie (een Booleaanse functie) opgeven en een reeks maken op basis van een andere reeks die bestaat uit die elementen van de oorspronkelijke reeks waarvoor het predicaat istrue, maar stoppen voordat het eerste element waarvoor het predicaat wordt geretourneerdfalse. Seq.skip retourneert een reeks die een opgegeven aantal van de eerste elementen van een andere reeks overslaat en de resterende elementen retourneert. Seq.skipWhile retourneert een reeks die de eerste elementen van een andere reeks overslaat zolang het predicaat retourneert trueen vervolgens de resterende elementen retourneert, beginnend met het eerste element waarvoor het predicaat retourneert false.

In het volgende codevoorbeeld ziet u het gedrag van en verschillen tussen Seq.takeWhile, Seq.skipen 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

De uitvoer is als volgt.

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

Sequenties transformeren

Seq.pairwise maakt een nieuwe reeks waarin opeenvolgende elementen van de invoerreeks worden gegroepeerd in 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.windowed is als Seq.pairwise, behalve dat in plaats van een reeks tuples te produceren, het produceert een reeks matrices die kopieën van aangrenzende elementen (een venster) uit de reeks bevatten. U geeft het aantal aangrenzende elementen op dat u in elke matrix wilt gebruiken.

In het volgende codevoorbeeld ziet u het gebruik van Seq.windowed. In dit geval is het aantal elementen in het venster 3. In het voorbeeld wordt printSeqgebruikgemaakt van , dat is gedefinieerd in het vorige codevoorbeeld.

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

De uitvoer is als volgt.

Initiële reeks:

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

Bewerkingen met meerdere reeksen

Seq.zip en Seq.zip3 nemen twee of drie reeksen en produceren een reeks tuples. Deze functies zijn net als de bijbehorende functies die beschikbaar zijn voor lijsten. Er is geen bijbehorende functionaliteit om één reeks te scheiden in twee of meer reeksen. Als u deze functionaliteit voor een reeks nodig hebt, converteert u de reeks naar een lijst en gebruikt u List.unzip.

Sorteren, vergelijken en groeperen

De sorteerfuncties die worden ondersteund voor lijsten, werken ook met reeksen. Dit omvat Seq.sort en Seq.sortBy. Deze functies doorlopen de hele reeks.

U vergelijkt twee reeksen met behulp van de functie Seq.compareWith . De functie vergelijkt opeenvolgende elementen op zijn beurt en stopt wanneer deze het eerste ongelijke paar tegenkomt. Eventuele aanvullende elementen dragen niet bij aan de vergelijking.

De volgende code toont het gebruik van 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.")

In de vorige code wordt alleen het eerste element berekend en onderzocht en het resultaat is -1.

Seq.countBy gebruikt een functie die een waarde genereert die een sleutel voor elk element wordt genoemd. Er wordt een sleutel gegenereerd voor elk element door deze functie aan te roepen op elk element. Seq.countBy retourneert vervolgens een reeks die de sleutelwaarden bevat en een telling van het aantal elementen dat elke waarde van de sleutel heeft gegenereerd.

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

De uitvoer is als volgt.

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

In de vorige uitvoer ziet u dat er 34 elementen van de oorspronkelijke reeks waren die de sleutel 1, 33 waarden hebben geproduceerd die de sleutel 2 en 33 waarden hebben geproduceerd die de sleutel 0 hebben geproduceerd.

U kunt elementen van een reeks groeperen door Seq.groupBy aan te roepen. Seq.groupBy neemt een reeks en een functie die een sleutel genereert van een element. De functie wordt uitgevoerd op elk element van de reeks. Seq.groupBy retourneert een reeks tuples, waarbij het eerste element van elke tuple de sleutel is en de tweede een reeks elementen die die sleutel produceren.

In het volgende codevoorbeeld ziet u het gebruik van Seq.groupBy het partitioneren van de reeks getallen van 1 tot 100 in drie groepen met de unieke sleutelwaarden 0, 1 en 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

De uitvoer is als volgt.

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

U kunt een reeks maken die dubbele elementen elimineert door Seq.distinct aan te roepen. Of u kunt Seq.distinctBy gebruiken, waarbij een functie voor het genereren van sleutels wordt aangeroepen op elk element. De resulterende reeks bevat elementen van de oorspronkelijke reeks met unieke sleutels; latere elementen die een dubbele sleutel voor een eerder element produceren, worden verwijderd.

Het volgende codevoorbeeld illustreert het gebruik van Seq.distinct. Seq.distinct wordt gedemonstreerd door reeksen te genereren die binaire getallen vertegenwoordigen en vervolgens te laten zien dat de enige afzonderlijke elementen 0 en 1 zijn.

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

De volgende code laat zien Seq.distinctBy door te beginnen met een reeks met negatieve en positieve getallen en het gebruik van de absolute waardefunctie als sleutelgenererende functie. In de resulterende reeks ontbreken alle positieve getallen die overeenkomen met de negatieve getallen in de reeks, omdat de negatieve getallen eerder in de reeks worden weergegeven en daarom worden geselecteerd in plaats van de positieve getallen met dezelfde absolute waarde of sleutel.

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

Lees- en cachereeksen

Seq.readonly maakt een alleen-lezen kopie van een reeks. Seq.readonly is handig wanneer u een verzameling voor lezen/schrijven hebt, zoals een matrix, en u de oorspronkelijke verzameling niet wilt wijzigen. Deze functie kan worden gebruikt om gegevenscapsulatie te behouden. In het volgende codevoorbeeld wordt een type gemaakt dat een matrix bevat. Een eigenschap geeft de matrix weer, maar in plaats van een matrix te retourneren, retourneert deze een reeks die is gemaakt op basis van de matrix met behulp van 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 maakt een opgeslagen versie van een reeks. Gebruik Seq.cache dit om herwaardering van een reeks te voorkomen of wanneer u meerdere threads hebt die een reeks gebruiken, maar u moet ervoor zorgen dat elk element slechts één keer wordt uitgevoerd. Wanneer u een reeks hebt die door meerdere threads wordt gebruikt, kunt u één thread hebben die de waarden voor de oorspronkelijke reeks opsommen en berekent, en de resterende threads kunnen de opgeslagen reeks in de cache gebruiken.

Berekeningen uitvoeren op reeksen

Eenvoudige rekenkundige bewerkingen zijn gelijk aan die van lijsten, zoals Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, enzovoort.

Seq.fold, Seq.reduce en Seq.scan zijn net als de bijbehorende functies die beschikbaar zijn voor lijsten. Reeksen ondersteunen een subset van de volledige variaties van deze functies die ondersteuning bieden. Zie Lijsten voor meer informatie en voorbeelden.

Zie ook