Sequenze

Una sequenza è una serie logica di elementi di un tipo. Le sequenze sono particolarmente utili quando si dispone di una raccolta ordinata di dati di grandi dimensioni, ma non si prevede necessariamente di usare tutti gli elementi. I singoli elementi di sequenza vengono calcolati solo come richiesto, quindi una sequenza può offrire prestazioni migliori rispetto a un elenco in situazioni in cui non vengono usati tutti gli elementi. Le sequenze sono rappresentate dal seq<'T> tipo , ovvero un alias per IEnumerable<T>. Pertanto, qualsiasi tipo .NET che implementa l'interfaccia IEnumerable<T> può essere usato come sequenza. Il modulo Seq fornisce supporto per le manipolazioni che coinvolgono sequenze.

Espressioni di sequenza

Un'espressione di sequenza è un'espressione che restituisce una sequenza. Le espressioni di sequenza possono assumere diverse forme. Il formato più semplice specifica un intervallo. Ad esempio, seq { 1 .. 5 } crea una sequenza che contiene cinque elementi, inclusi gli endpoint 1 e 5. È anche possibile specificare un incremento (o decremento) tra due periodi doppi. Ad esempio, il codice seguente crea la sequenza di multipli di 10.

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

Le espressioni di sequenza sono costituite da espressioni F# che producono valori della sequenza. È anche possibile generare valori a livello di codice:

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

Nell'esempio precedente viene usato l'operatore , che consente di specificare un'espressione -> il cui valore diventerà parte della sequenza. È possibile usare -> solo se ogni parte del codice che segue restituisce un valore.

In alternativa, è possibile specificare la do parola chiave , con un valore facoltativo yield che segue:

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
}

Il codice seguente genera un elenco di coppie di coordinate insieme a un indice in una matrice che rappresenta la griglia. Si noti che per la prima for espressione è necessario specificare un oggetto 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)
}

Un'espressione if usata in una sequenza è un filtro. Ad esempio, per generare una sequenza di soli numeri primi, presupponendo che si disponga di una funzione isprime di tipo int -> bool, costruire la sequenza come indicato di seguito.

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

Come accennato in precedenza, do è necessario perché non esiste un else ramo che passa con .if Se si tenta di usare ->, verrà visualizzato un errore che indica che non tutti i rami restituiscono un valore.

Parola chiave yield!

In alcuni casi, è possibile includere una sequenza di elementi in un'altra sequenza. Per includere una sequenza all'interno di un'altra sequenza, è necessario usare la yield! parola chiave :

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

Un altro modo di pensare yield! è che appiattisce una sequenza interna e quindi lo include nella sequenza contenitore.

Quando yield! viene usato in un'espressione, tutti gli altri valori singoli devono usare la yield parola chiave :

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

L'esempio precedente produrrà il valore di x oltre a tutti i valori da 1 a x per ogni x.

Esempi

Il primo esempio usa un'espressione di sequenza che contiene un'iterazione, un filtro e un risultato per generare una matrice. Questo codice stampa una sequenza di numeri primi compresa tra 1 e 100 nella 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

Nell'esempio seguente viene creata una tabella di moltiplicazione costituita da tuple di tre elementi, ognuna costituita da due fattori e dal prodotto:

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

Nell'esempio seguente viene illustrato l'uso di yield! per combinare singole sequenze in una singola sequenza finale. In questo caso, le sequenze per ogni sottoalbero in un albero binario vengono concatenate in una funzione ricorsiva per produrre la sequenza finale.

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

Utilizzo di sequenze

Le sequenze supportano molte delle stesse funzioni degli elenchi. Le sequenze supportano anche operazioni come il raggruppamento e il conteggio usando funzioni di generazione della chiave. Le sequenze supportano anche funzioni più diverse per l'estrazione di sottosequenze.

Molti tipi di dati, ad esempio elenchi, matrici, set e mappe, sono sequenze implicite perché sono raccolte enumerabili. Una funzione che accetta una sequenza come argomento funziona con uno dei tipi di dati F# comuni, oltre a qualsiasi tipo di dati .NET che implementa System.Collections.Generic.IEnumerable<'T>. A differenza di una funzione che accetta un elenco come argomento, che può accettare solo elenchi. Il tipo seq<'T> è un'abbreviazione di tipo per IEnumerable<'T>. Ciò significa che qualsiasi tipo che implementa l'oggetto generico System.Collections.Generic.IEnumerable<'T>, che include matrici, elenchi, set e mappe in F#, nonché la maggior parte dei tipi di raccolta .NET, è compatibile con il seq tipo e può essere usato ovunque sia prevista una sequenza.

Funzioni di modulo

Il modulo Seq nello spazio dei nomi FSharp.Collections contiene funzioni per l'uso delle sequenze. Queste funzioni funzionano anche con elenchi, matrici, mappe e set, perché tutti questi tipi sono enumerabili e pertanto possono essere considerati come sequenze.

Creazione di sequenze

È possibile creare sequenze usando espressioni di sequenza, come descritto in precedenza o usando determinate funzioni.

È possibile creare una sequenza vuota usando Seq.empty oppure creare una sequenza di un solo elemento specificato usando Seq.singleton.

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

È possibile usare Seq.init per creare una sequenza per cui vengono creati gli elementi usando una funzione specificata. È anche possibile specificare una dimensione per la sequenza. Questa funzione è simile a List.init, ad eccezione del fatto che gli elementi non vengono creati fino a quando non si scorre la sequenza. Il codice seguente illustra l'uso di Seq.init.

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

L'output è

0 10 20 30 40

Usando Seq.ofArray e Seq.ofList'T>< Function, è possibile creare sequenze da matrici ed elenchi. Tuttavia, è anche possibile convertire matrici ed elenchi in sequenze usando un operatore cast. Entrambe le tecniche sono illustrate nel codice seguente.

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

Usando Seq.cast, è possibile creare una sequenza da una raccolta tipizzata in modo debole, ad esempio quelle definite in System.Collections. Tali raccolte tipate in modo debole hanno il tipo di System.Object elemento e vengono enumerate usando il tipo non generico System.Collections.Generic.IEnumerable&#96;1 . Il codice seguente illustra l'uso di Seq.cast per convertire un oggetto System.Collections.ArrayList in una sequenza.

open System

let arr = ResizeArray<int>(10)

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

let seqCast = Seq.cast arr

È possibile definire sequenze infinite usando la funzione Seq.initInfinite . Per una sequenza di questo tipo, si fornisce una funzione che genera ogni elemento dall'indice dell'elemento. Le sequenze infinite sono possibili a causa della valutazione lazy; Gli elementi vengono creati in base alle esigenze chiamando la funzione specificata. L'esempio di codice seguente genera una sequenza infinita di numeri a virgola mobile, in questo caso la serie alternata di quadrati di interi successivi.

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 genera una sequenza da una funzione di calcolo che accetta uno stato e la trasforma per produrre ogni elemento successivo nella sequenza. Lo stato è solo un valore usato per calcolare ogni elemento e può cambiare man mano che viene calcolato ogni elemento. Il secondo argomento di Seq.unfold è il valore iniziale utilizzato per avviare la sequenza. Seq.unfold usa un tipo di opzione per lo stato, che consente di terminare la sequenza restituendo il None valore . Il codice seguente illustra due esempi di sequenze e seq1fib, generati da un'operazione unfold . Il primo, seq1, è solo una sequenza semplice con numeri fino a 20. Il secondo, fib, usa unfold per calcolare la sequenza Di Fibonacci. Poiché ogni elemento nella sequenza di Fibonacci è la somma dei due numeri di Fibonacci precedenti, il valore di stato è una tupla costituita dai due numeri precedenti nella sequenza. Il valore iniziale è (0,1), i primi due numeri nella sequenza.

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

L'output è il seguente:

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 

Il codice seguente è un esempio che usa molte delle funzioni del modulo di sequenza descritte qui per generare e calcolare i valori di sequenze infinite. L'esecuzione del codice potrebbe richiedere alcuni minuti.

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

Ricerca e ricerca di elementi

Le sequenze supportano la funzionalità disponibile con elenchi: Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind e Seq.tryFindIndex. Le versioni di queste funzioni disponibili per le sequenze valutano la sequenza solo fino all'elemento cercato. Per esempi, vedere Elenchi.

Recupero di sottosequenze

Seq.filter e Seq.choose sono simili alle funzioni corrispondenti disponibili per gli elenchi, ad eccezione del fatto che il filtro e la scelta non si verificano finché gli elementi della sequenza non vengono valutati.

Seq.truncate crea una sequenza da un'altra sequenza, ma limita la sequenza a un numero specificato di elementi. Seq.take crea una nuova sequenza che contiene solo un numero specificato di elementi dall'inizio di una sequenza. Se nella sequenza sono presenti meno elementi di quelli da accettare, Seq.take genera un'eccezione System.InvalidOperationException. La differenza tra Seq.take e Seq.truncate è che Seq.truncate non genera un errore se il numero di elementi è minore del numero specificato.

Il codice seguente illustra il comportamento di e le differenze tra Seq.truncate e 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

L'output, prima che si verifichi l'errore, è il seguente.

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

Usando Seq.takeWhile, è possibile specificare una funzione predicato (una funzione booleana) e creare una sequenza da un'altra sequenza costituita da tali elementi della sequenza originale per cui il predicato è true, ma arrestare prima del primo elemento per cui il predicato restituisce false. Seq.skip restituisce una sequenza che ignora un numero specificato dei primi elementi di un'altra sequenza e restituisce gli elementi rimanenti. Seq.skipWhile restituisce una sequenza che ignora i primi elementi di un'altra sequenza purché il predicato restituisca true, quindi restituisce gli elementi rimanenti, a partire dal primo elemento per il quale il predicato restituisce false.

Nell'esempio di codice seguente viene illustrato il comportamento di e le differenze tra Seq.takeWhile, Seq.skipe 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

L'output è indicato di seguito.

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

Trasformazione di sequenze

Seq.pairwise crea una nuova sequenza in cui gli elementi successivi della sequenza di input vengono raggruppati in tuple.

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 è simile Seq.pairwisea , ad eccezione del fatto che invece di produrre una sequenza di tuple, produce una sequenza di matrici che contengono copie di elementi adiacenti (una finestra) dalla sequenza. Specificare il numero di elementi adiacenti desiderati in ogni matrice.

L'esempio di codice seguente illustra l'uso di Seq.windowed. In questo caso il numero di elementi nella finestra è 3. Nell'esempio viene usato printSeq, definito nell'esempio di codice precedente.

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

L'output è indicato di seguito.

Sequenza iniziale:

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

Operazioni con più sequenze

Seq.zip e Seq.zip3 accettano due o tre sequenze e producono una sequenza di tuple. Queste funzioni sono simili alle funzioni corrispondenti disponibili per gli elenchi. Non esiste alcuna funzionalità corrispondente per separare una sequenza in due o più sequenze. Se è necessaria questa funzionalità per una sequenza, convertire la sequenza in un elenco e usare List.unzip.

Ordinamento, confronto e raggruppamento

Le funzioni di ordinamento supportate per gli elenchi funzionano anche con le sequenze. Sono inclusi Seq.sort e Seq.sortBy. Queste funzioni consentono di scorrere l'intera sequenza.

Si confrontano due sequenze usando la funzione Seq.compareWith . La funzione confronta gli elementi successivi a sua volta e si arresta quando rileva la prima coppia diversa. Eventuali elementi aggiuntivi non contribuiscono al confronto.

Il codice seguente illustra l'uso di 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.")

Nel codice precedente viene calcolato e esaminato solo il primo elemento e il risultato è -1.

Seq.countBy accetta una funzione che genera un valore denominato chiave per ogni elemento. Una chiave viene generata per ogni elemento chiamando questa funzione su ogni elemento. Seq.countBy restituisce quindi una sequenza che contiene i valori chiave e un conteggio del numero di elementi che hanno generato ogni valore della chiave.

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

L'output è indicato di seguito.

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

L'output precedente mostra che sono presenti 34 elementi della sequenza originale che hanno prodotto la chiave 1, 33 valori che hanno prodotto la chiave 2 e 33 valori che hanno prodotto la chiave 0.

È possibile raggruppare gli elementi di una sequenza chiamando Seq.groupBy. Seq.groupBy accetta una sequenza e una funzione che genera una chiave da un elemento. La funzione viene eseguita su ogni elemento della sequenza. Seq.groupBy restituisce una sequenza di tuple, in cui il primo elemento di ogni tupla è la chiave e il secondo è una sequenza di elementi che producono tale chiave.

Nell'esempio di codice seguente viene illustrato l'uso di Seq.groupBy per partizionare la sequenza di numeri da 1 a 100 in tre gruppi con valori di chiave distinti 0, 1 e 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

L'output è indicato di seguito.

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

È possibile creare una sequenza che elimina gli elementi duplicati chiamando Seq.distinct. In alternativa, è possibile usare Seq.distinctBy, che accetta una funzione di generazione della chiave da chiamare su ogni elemento. La sequenza risultante contiene elementi della sequenza originale con chiavi univoce; gli elementi successivi che producono una chiave duplicata in un elemento precedente vengono eliminati.

Nell'esempio di codice seguente viene illustrato l'uso di Seq.distinct. Seq.distinct viene dimostrato generando sequenze che rappresentano numeri binari e quindi mostrando che gli unici elementi distinti sono 0 e 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

Il codice seguente illustra Seq.distinctBy l'avvio con una sequenza che contiene numeri negativi e positivi e usa la funzione di valore assoluto come funzione di generazione della chiave. La sequenza risultante manca tutti i numeri positivi che corrispondono ai numeri negativi nella sequenza, perché i numeri negativi vengono visualizzati in precedenza nella sequenza e pertanto vengono selezionati anziché i numeri positivi con lo stesso valore assoluto o chiave.

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

Sequenze di sola lettura e memorizzate nella cache

Seq.readonly crea una copia di sola lettura di una sequenza. Seq.readonly è utile quando si dispone di una raccolta di lettura/scrittura, ad esempio una matrice, e non si vuole modificare la raccolta originale. Questa funzione può essere usata per mantenere l'incapsulamento dei dati. Nell'esempio di codice seguente viene creato un tipo che contiene una matrice. Una proprietà espone la matrice, ma anziché restituire una matrice, restituisce una sequenza creata dalla matrice usando 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 crea una versione archiviata di una sequenza. Usare Seq.cache per evitare la rivalutazione di una sequenza o quando si dispone di più thread che usano una sequenza, ma è necessario assicurarsi che ogni elemento venga eseguito una sola volta. Quando si dispone di una sequenza usata da più thread, è possibile avere un thread che enumera e calcola i valori per la sequenza originale e i thread rimanenti possono usare la sequenza memorizzata nella cache.

Esecuzione di calcoli sulle sequenze

Le semplici operazioni aritmetiche sono simili a quelle degli elenchi, ad esempio Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy e così via.

Seq.fold, Seq.reduce e Seq.scan sono simili alle funzioni corrispondenti disponibili per gli elenchi. Le sequenze supportano un subset delle varianti complete di queste funzioni che elencano il supporto. Per altre informazioni ed esempi, vedere Elenchi.

Vedi anche