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 -> bool
hebt, 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 x
waarde 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`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 seq1
fib
, die worden gegenereerd door een unfold
bewerking. De eerste, seq1
is slechts een eenvoudige reeks met getallen tot 20. De tweede, fib
wordt 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 true
en 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.skip
en 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 printSeq
gebruikgemaakt 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.