Sequenze (F#)
Una sequenza è una serie logica di elementi dello stesso tipo. Le sequenze risultano particolarmente utili nel caso in cui si disponga di un insieme di dati ordinato e di grandi dimensioni, ma non si prevede di utilizzare necessariamente tutti gli elementi. I singoli elementi della sequenza vengono calcolati solo se necessario, pertanto una sequenza può fornire prestazioni migliori rispetto a un elenco nei casi in cui non vengano utilizzati tutti gli elementi. Le sequenze vengono rappresentate dal tipo seq<'T>, un alias per IEnumerable<T>. Qualsiasi tipo .NET Framework che implementa System.IEnumerable può essere pertanto utilizzato come sequenza. Il modulo Seq fornisce supporto per le modifiche che coinvolgono le sequenze.
Espressioni sequenza
Un'espressione sequenza è un'espressione che restituisce una sequenza. Le espressioni sequenza possono assumere varie forme. La forma più semplice specifica un intervallo. seq { 1 .. 5 } crea ad esempio una sequenza contenente cinque elementi, inclusi gli endpoint 1 e 5. È inoltre possibile specificare un incremento (o un decremento) tra due periodi doppi. Nel codice seguente viene ad esempio creata la sequenza di multipli di 10.
// Sequence that has an increment.
seq { 0 .. 10 .. 100 }
Le espressioni sequenza sono costituite da espressioni F# che producono valori della sequenza. Possono utilizzare la parola chiave yield per produrre valori che divengono parte della sequenza.
Di seguito è riportato un esempio.
seq { for i in 1 .. 10 do yield i * i }
È possibile utilizzare l'operatore -> anziché la parola chiave yield, nel qual caso è possibile omettere la parola chiave do, come nell'esempio indicato di seguito.
seq { for i in 1 .. 10 -> i * i }
Nel codice seguente viene generato un elenco di coordinate insieme a un indice in una matrice che rappresenta la griglia.
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)
}
Un'espressione if utilizzata in una sequenza corrisponde a un filtro. Per generare ad esempio una sequenza di soli numeri primi, presupponendo che si disponga di una funzione isprime di tipo int -> bool, costruire la sequenza nel modo indicato di seguito.
seq { for n in 1 .. 100 do if isprime n then yield n }
Se si utilizza la parola chiave yield o -> in un'iterazione, ogni iterazione dovrebbe generare un solo elemento della sequenza. Se ogni iterazione produce una sequenza di elementi, utilizzare la parola chiave yield!. In tal caso, gli elementi generati in ogni iterazione vengono concatenati per produrre la sequenza finale.
È possibile combinare più espressioni insieme in un'espressione sequenza. Vengono concatenati gli elementi generati da ogni espressione. Per un esempio, vedere la sezione "Esempi" del presente argomento.
Esempi
Nel primo esempio viene utilizzata un'espressione sequenza contenente un'iterazione, un filtro e una parola chiave yield per generare una matrice. In questo codice viene visualizzata una sequenza di numeri primi compresi 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 yield n }
for x in aSequence do
printfn "%d" x
Nel codice seguente viene utilizzata la parola chiave yield per creare una tavola pitagorica costituita da tuple di tre elementi, ognuna rappresentata da due fattori e dal prodotto.
let multiplicationTable =
seq { for i in 1..9 do
for j in 1..9 do
yield (i, j, i*j) }
Nell'esempio seguente viene illustrato l'utilizzo di yield! per combinare singole sequenze in una singola sequenza finale. In questo caso, le sequenze per ogni sottoalbero in una struttura ad albero binaria sono 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 inoltre operazioni quali i raggruppamenti e i conteggi mediante funzioni di generazione di chiavi. Le sequenze supportano anche funzioni più varie per l'estrazione di sottosequenze.
Molti tipi di dati, ad esempio elenchi, matrici, set e mappe, sono sequenze a livello implicito, in quanto insiemi enumerabili. Una funzione che utilizza una sequenza come argomento è compatibile con qualsiasi tipo di dati F# comune, oltre a qualsiasi tipo di dati .NET Framework che implementa IEnumerable<T>. Contrapporre questa funzione a un'altra che utilizza un elenco come un argomento, che può esclusivamente utilizzare elenchi. Il tipo seq<'a> è un'abbreviazione di tipo per IEnumerable<'a>. Ciò significa che qualsiasi tipo che implementa l'elemento IEnumerable<T> generico, che include matrici, elenchi, set e mappe in F#, nonché la maggior parte dei tipi di insieme .NET Framework, è compatibile con il tipo seq e può essere utilizzato laddove sia prevista una sequenza.
Funzioni del modulo
Il modulo Seq nello spazio dei nomi Microsoft.FSharp.Collections contiene funzioni per l'utilizzo delle sequenze. Queste funzioni sono compatibili anche con elenchi, matrici, mappe e set, poiché si tratta di tipi enumerabili e pertanto possono essere considerati come sequenze.
Creazione di sequenze
È possibile creare sequenze tramite espressioni sequenza, come descritto in precedenza, o tramite determinate funzioni.
È possibile creare una sequenza vuota tramite Seq.empty oppure una sequenza di un solo elemento specificato tramite Seq.singleton.
let seqEmpty = Seq.empty
let seqOne = Seq.singleton 10
È possibile utilizzare Seq.init per creare una sequenza i cui elementi vengono creati tramite una funzione fornita. Viene inoltre fornita una dimensione per la sequenza. Questa funzione è analoga a List.init, ad eccezione del fatto che gli elementi non vengono creati finché non si scorre l'intera sequenza. Nel codice riportato di seguito viene illustrato l'utilizzo 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
Tramite Seq.ofArray e Funzione Seq.ofList<'T> (F#) è possibile creare sequenze da matrici ed elenchi. È tuttavia possibile convertire matrici ed elenchi in sequenze tramite un operatore di cast. Entrambe le tecniche vengono 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
Tramite Seq.cast è possibile creare una sequenza da un insieme con tipizzazione debole (come nei casi definiti in System.Collections). Tali insiemi con tipizzazione debole dispongono del tipo di elemento Object e vengono enumerati tramite il tipo IEnumerable<T> non generico. Nel codice seguente viene illustrato l'utilizzo di Seq.cast per convertire ArrayList in una sequenza.
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
È possibile definire sequenze infinite tramite la funzione Seq.initInfinite. Per questo tipo di sequenze viene fornita una funzione che genera ogni elemento dall'indice dell'elemento. Le sequenze infinite sono dovute a una valutazione non approfondita. Gli elementi vengono creati in base alle esigenze chiamando la funzione specificata. Nell'esempio di codice seguente viene prodotta una sequenza infinita di numeri a virgola mobile (in questo caso, una serie alternata di reciproci di quadrati di interi consecutivi).
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 lo trasforma per produrre ogni elemento consecutivo nella sequenza. Lo stato rappresenta solo un valore utilizzato per calcolare ogni elemento e può variare contestualmente al calcolo di ogni elemento. Il secondo argomento di Seq.unfold rappresenta il valore iniziale utilizzato per avviare la sequenza. Seq.unfold utilizza un tipo di opzione per lo stato che consente di terminare la sequenza restituendo il valore None. Nel codice seguente vengono indicati due esempi di sequenze, seq1 e fib, generate da un'operazione unfold. La prima, seq1, rappresenta una semplice sequenza con numeri fino a 100. La seconda, fib, utilizza unfold per calcolare la sequenza di Fibonacci. Poiché ogni elemento della sequenza di Fibonacci è la somma dei due numeri di Fibonacci precedenti, il valore dello stato è una tupla costituita dai due numeri precedenti nella sequenza. Il valore iniziale è (1,1), che corrisponde ai primi due numeri nella sequenza.
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
L'output è indicato di seguito:
La sequenza seq1 contiene i numeri da 0 a 20.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
La sequenza fib contiene i numeri di Fibonacci.
2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Il codice seguente costituisce un esempio che utilizza molte delle funzioni del modulo di sequenze qui descritto per generare e calcolare i valori di sequenze infinite. L'esecuzione del codice potrebbe richiedere alcuni minuti.
// 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)
Ricerca e individuazione di elementi
Le sequenze supportano le funzionalità disponibili con gli 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 ricercato. Per alcuni esempi, vedere Elenchi.
Acquisizione di sottosequenze
Seq.filter e Seq.choose sono analoghi alle funzioni corrispondenti disponibili per gli elenchi, ad eccezione del fatto che le operazioni di filtro e selezione si verificano solo una volta completata la valutazione degli elementi della sequenza.
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 contenente esclusivamente un numero specificato di elementi dall'inizio di una sequenza. Se nella sequenza è presente un numero inferiore di elementi rispetto a quelli specificati, Seq.take genera un'eccezione InvalidOperationException. La differenza tra Seq.take e Seq.truncate consiste nel fatto che Seq.truncate non produce un errore se il numero di elementi è inferiore al numero specificato.
Nell'esempio di codice seguente vengono illustrati il comportamento 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
Prima che si verifichi l'errore, l'output corrisponde a quanto indicato di seguito.
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
Tramite Seq.takeWhile è possibile specificare una funzione di predicato (funzione booleana) e creare una sequenza da un'altra sequenza costituita dagli elementi della sequenza originale per cui il predicato è true, che tuttavia si interromperà prima di raggiungere il primo elemento per il quale il predicato restituisce false. Seq.skip restituisce una sequenza che ignora un numero specificato dei primi elementi di un'altra sequenza e restituisce i restanti elementi. Seq.skipWhile restituisce una sequenza che ignora i primi elementi di un'altra sequenza finché il predicato restituisce true, quindi restituisce i restanti elementi a partire dal primo elemento per cui il predicato restituisce false.
Nell'esempio di codice seguente vengono illustrati il comportamento e le differenze tra Seq.takeWhile, Seq.skip e 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 nella quale gli elementi consecutivi 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
Seq.windowed è analogo a Seq.pairwise, ad eccezione del fatto che, anziché produrre una sequenza di tuple, produce una sequenza di matrici che contengono copie di elementi adiacenti (una finestra) della sequenza. Viene specificato il numero di elementi adiacenti desiderato in ogni matrice.
Nell'esempio di codice seguente viene illustrato l'utilizzo di Seq.windowed. In questo caso il numero di elementi nella finestra è pari a 3. L'esempio utilizza l'oggetto printSeq, definito nell'esempio 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 utilizzano due o tre sequenze e producono una sequenza di tuple. Queste funzioni sono analoghe alle funzioni corrispondenti disponibili per gli elenchi. Non sono presenti funzionalità corrispondenti per separare una sequenza in due o più sequenze. Se questa funzionalità è necessaria per una sequenza, convertire la sequenza in un elenco e utilizzare List.unzip.
Ordinamento, confronto e raggruppamento
Le funzioni di ordinamento supportate per gli elenchi possono essere utilizzate anche con le sequenze. Tra queste sono incluse Seq.sort e Seq.sortBy, che scorrono l'intera sequenza.
È possibile confrontare due sequenze tramite la funzione Seq.compareWith. La funzione confronta a sua volta elementi consecutivi e si arresta nel momento in cui incontra la prima coppia disuguale. Al confronto non contribuiscono ulteriori elementi.
Nell'esempio di codice riportato di seguito viene illustrato come utilizzare 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 ed esaminato solo il primo elemento e il risultato è -1.
Seq.countBy utilizza una funzione che genera un valore denominato chiave per ogni elemento. Per ogni elemento viene generata una chiave chiamando questa funzione su ogni elemento. Seq.countBy restituisce quindi una sequenza contenente i valori della chiave e un conteggio del numero di elementi che genera ogni valore della chiave.
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
L'output è indicato di seguito.
(1, 34) (2, 33) (0, 33)
L'output precedente indica che 34 elementi della sequenza originale hanno prodotto la chiave 1, 33 valori hanno prodotto la chiave 2 e 33 valori hanno prodotto la chiave 0.
È possibile raggruppare gli elementi di una sequenza chiamando Seq.groupBy. Seq.groupBy utilizza 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 la chiave stessa.
Nell'esempio di codice seguente viene mostrato l'utilizzo di Seq.groupBy per partizionare la sequenza di numeri da 1 a 100 in tre gruppi con valori di chiave distinct 0, 1 e 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
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 elementi duplicati chiamando Seq.distinct. È in alternativa possibile utilizzare Seq.distinctBy, che utilizza una funzione di generazione di chiavi da chiamare su ogni elemento. La sequenza risultante contiene elementi della sequenza originale che dispongono di chiavi univoche. Gli elementi successivi che producono una chiave duplicata per un elemento precedente vengono ignorati.
Nell'esempio di codice seguente viene illustrato l'utilizzo di Seq.distinct. Seq.distinct viene indicato generando sequenze che rappresentano numeri binari e mostrando quindi 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
Nel codice seguente viene illustrato Seq.distinctBy a partire da una sequenza che contiene numeri negativi e positivi e utilizzando la funzione di valore assoluto come funzione di generazione di chiavi. La sequenza risultante è priva di tutti i numeri positivi corrispondenti ai numeri negativi nella sequenza, poiché i numeri negativi vengono visualizzati in un punto precedente della sequenza e vengono pertanto selezionati al posto dei numeri positivi con lo stesso valore assoluto o chiave.
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
Sequenze di sola lettura e memorizzate nella cache
Seq.readonly crea una copia di sola lettura di una sequenza. Seq.readonly risulta utile nel caso in cui si disponga di un insieme di lettura e scrittura, ad esempio una matrice, e non si desideri modificare l'insieme originale. Questa funzione può essere utilizzata per mantenere l'incapsulamento dei dati. Nell'esempio di codice seguente viene creato un tipo contenente una matrice. Una proprietà espone la matrice, ma anziché restituire una matrice, restituisce una sequenza creata dalla matrice tramite 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. Utilizzare Seq.cache per evitare un'ulteriore rivalutazione di una sequenza o se più thread utilizzano una sequenza ma è necessario accertarsi di intervenire una sola volta su ogni elemento. Nel caso di una sequenza utilizzata da più thread, un thread può enumerare e calcolare i valori per la sequenza originale e gli altri possono utilizzare la sequenza memorizzata nella cache.
Esecuzione di calcoli sulle sequenze
Le operazioni aritmetiche semplici sono analoghe a quelle relative agli elenchi, ad esempio Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy e così via.
Seq.fold, Seq.reduce e Seq.scan sono analoghe alle funzioni corrispondenti disponibili per gli elenchi. Le sequenze supportano un subset delle variazioni complete di queste funzioni supportate dagli elenchi. Per ulteriori informazioni ed esempi, vedere Elenchi (F#).
Vedere anche
Riferimenti
Altre risorse
Riferimenti per il linguaggio F#
Cronologia delle modifiche
Data |
Cronologia |
Motivo |
---|---|---|
Maggio 2010 |
Sono stati migliorati degli esempi di codice. |
Miglioramento delle informazioni. |