Séquences

Une séquence est une série logique d’éléments d’un même type. Les séquences sont notamment utiles lorsque vous disposez d’une collection de données volumineuse et ordonnée, mais ne vous attendez pas nécessairement à utiliser tous les éléments. Les éléments de séquence individuels sont calculés uniquement en fonction des besoins, de sorte qu’une séquence peut fournir de meilleures performances qu’une liste dans les situations où tous les éléments ne sont pas utilisés. Les séquences sont représentées par le type seq<'T>, qui est un alias pour IEnumerable<T>. Par conséquent, tout type de .NET qui implémente l’interface IEnumerable<T> peut être utilisé comme séquence. Le module Seq prend en charge les manipulations impliquant des séquences.

Expressions de séquence

Une expression de séquence est une expression qui prend la valeur d’une séquence. Les expressions de séquence peuvent prendre plusieurs formes. La forme la plus simple indique une plage. Par exemple, seq { 1 .. 5 } crée une séquence qui contient cinq éléments, y compris les points de terminaison 1 et 5. Vous pouvez également spécifier une incrémentation (ou décrémentation) entre deux périodes doubles. Par exemple, le code suivant crée la séquence de multiples de 10.

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

Les expressions de séquence sont constituées d’expressions F# qui produisent les valeurs de la séquence. Vous pouvez également générer des valeurs par programmation :

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

L’exemple précédent utilise l’opérateur ->, qui vous permet de spécifier une expression dont la valeur devient une partie de la séquence. Vous ne pouvez utiliser -> que si chaque partie du code qui suit l’opérateur retourne une valeur.

Vous pouvez également spécifier le mot clé do, suivi d’une option yield facultative :

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
}

Le code suivant génère une liste de paires de coordonnées, ainsi qu’un index dans un tableau qui représente la grille. Notez que la première expression for nécessite un do à spécifier.

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

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

Une expression if utilisée dans une séquence est un filtre. Par exemple, pour générer une séquence de nombres premiers uniquement, en supposant que vous disposez d’une fonction isprime de type int -> bool, construisez la séquence comme suit.

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

Comme mentionné précédemment, do est nécessaire ici, car aucune branche else ne va avec le if. Si vous essayez d’utiliser ->, vous obtenez une erreur indiquant que toutes les branches ne retournent pas une valeur.

Le mot clé yield!

Parfois, vous pouvez souhaiter inclure une séquence d’éléments dans une autre séquence. Pour inclure une séquence dans une autre séquence, vous devez utiliser le mot clé yield! :

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

Une autre façon de penser yield! est qu’il aplatit une séquence interne, puis inclut cela dans la séquence contenante.

Lorsque yield! est utilisé dans une expression, toutes les autres valeurs uniques doivent utiliser le mot clé yield :

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

L’exemple précédent génère la valeur x en plus de toutes les valeurs de 1 à x pour chaque x.

Exemples

Le premier exemple utilise une expression de séquence qui contient une itération, un filtre et un rendement pour générer un tableau. Ce code imprime une séquence de nombres premiers compris entre 1 et 100 dans la 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

L’exemple suivant crée une table de multiplication composée de tuples de trois éléments, chacune composée de deux facteurs et du produit :

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

L’exemple suivant illustre l’utilisation de yield! pour combiner des séquences individuelles en une seule séquence finale. Dans ce cas, les séquences de chaque sous-arborescence d’une arborescence binaire sont concaténées en une fonction récursive pour produire la séquence 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

Utilisation de séquences

Les séquences prennent en charge la plupart des mêmes fonctions que les listes. Les séquences prennent également en charge les opérations telles que le regroupement et le comptage à l’aide de fonctions de génération de clés. Les séquences prennent également en charge des fonctions plus diversifiées pour extraire des sous-séquences.

De nombreux types de données, tels que les listes, les tableaux, les jeux et les mappages, forment implicitement des séquences, car elles sont des collections énumérables. Une fonction qui prend une séquence comme argument fonctionne avec l’un des types de données F# courants, en plus de tout type de données .NET qui implémente System.Collections.Generic.IEnumerable<'T>. Comparez cela à une fonction qui prend une liste comme argument, qui ne peut prendre que des listes. Le type seq<'T> est une abréviation de type pour IEnumerable<'T>. Cela signifie que tout type qui implémente le générique System.Collections.Generic.IEnumerable<'T>, qui inclut des tableaux, des listes, des jeux et des mappages dans F#, ainsi que la plupart des types de collection .NET, est compatible avec le type seq et peut être utilisé partout où une séquence est attendue.

Fonctions de module

Le module Seq dans l’espace de noms FSharp.Collections contient des fonctions permettant d’utiliser des séquences. Ces fonctions fonctionnent également avec des listes, des tableaux, des cartes et des jeux, car tous ces types sont énumérables et peuvent donc être traités comme des séquences.

Création de séquences

Vous pouvez créer des séquences à l’aide d’expressions de séquence, comme décrit précédemment, ou à l’aide de certaines fonctions.

Vous pouvez créer une séquence vide à l’aide de Seq.empty, ou vous pouvez créer une séquence d’un seul élément spécifié à l’aide de Seq.singleton.

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

Vous pouvez utiliser Seq.init pour créer une séquence dont les éléments sont créés à l’aide d’une fonction que vous fournissez. Vous fournissez également une taille pour la séquence. Cette fonction est identique à List.init, sauf que les éléments ne sont pas créés qu’après itération dans la séquence. Le code suivant illustre l’utilisation de Seq.init.

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

La sortie est la suivante :

0 10 20 30 40

En utilisant la fonction Seq.ofArray et Seq.ofList<'T> Function, vous pouvez créer des séquences à partir de tableaux et de listes. Toutefois, vous pouvez également convertir des tableaux et des listes en séquences à l’aide d’un opérateur de cast. Les deux techniques sont présentées dans le code suivant.

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

À l’aide de Seq.cast, vous pouvez créer une séquence à partir d’une collection faiblement typée, telle que celles définies dans System.Collections. Ces collections faiblement typées présentent le type d’élément System.Object et sont énumérées à l’aide du type non générique System.Collections.Generic.IEnumerable&#96;1. Le code suivant illustre comment utiliser Seq.cast pour convertir un System.Collections.ArrayList en séquence.

open System

let arr = ResizeArray<int>(10)

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

let seqCast = Seq.cast arr

Vous pouvez définir des séquences infinies à l’aide de la fonction Seq.initInfinite. Pour ce type de séquence, vous fournissez une fonction qui génère chaque élément à partir de l’index de l’élément. Les séquences infinies sont possibles en raison d’une évaluation différée. Les éléments sont créés en fonction des besoins en appelant la fonction spécifiée. L’exemple de code suivant produit une séquence infinie de nombres à virgule flottante ; dans ce cas, il s’agit de la série alternée de réciproques de carrés d’entiers successifs.

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 génère une séquence à partir d’une fonction de calcul qui prend un état et le transforme pour produire chaque élément suivant dans la séquence. L’état est simplement une valeur utilisée pour calculer chaque élément et peut changer à mesure que chaque élément est calculé. Le deuxième argument de Seq.unfold est la valeur initiale utilisée pour démarrer la séquence. Seq.unfold utilise un type d’option pour l’état, qui vous permet de terminer la séquence en retournant la valeur None. Le code suivant montre deux exemples de séquences, seq1 et fib, qui sont générées par une opération de unfold. Le premier, seq1, est une séquence simple avec des nombres jusqu’à 20. Le deuxième, fib, utilise unfold pour calculer la séquence Fibonacci. Comme chaque élément de la séquence Fibonacci est la somme des deux nombres Fibonacci précédents, la valeur d’état est un tuple qui se compose des deux nombres précédents dans la séquence. La valeur initiale est (0,1), les deux premiers nombres de la séquence.

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

La sortie se présente comme suit :

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 

Le code suivant est un exemple qui utilise la plupart des fonctions de module de séquence décrites ici pour générer et calculer les valeurs des séquences infinies. Le codage peut prendre quelques minutes.

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

Recherche d’éléments

Les séquences prennent en charge les fonctionnalités disponibles avec des listes : Seq.exists, Seq.exists2, Seq.find, Seq.findIndex, Seq.pick, Seq.tryFind et Seq.tryFindIndex. Les versions de ces fonctions disponibles pour les séquences évaluent la séquence uniquement jusqu’à l’élément recherché. Pour obtenir des exemples, consultez les Listes.

Obtention de sous-séquences

Seq.filter et Seq.choose sont semblables aux fonctions correspondantes disponibles pour les listes, sauf que le filtrage et le choix ne se produisent pas tant que les éléments de séquence ne sont pas évalués.

Seq.truncate crée une séquence à partir d’une autre séquence, mais limite la séquence à un nombre d’éléments indiqué. Seq.take crée une séquence qui contient uniquement un nombre d’éléments indiqué à partir du début d’une séquence. Si la séquence que vous avez indiquée présente moins d’éléments à prendre, Seq.take lève un System.InvalidOperationException. La différence entre Seq.take et Seq.truncate est que Seq.truncate n’entraîne pas d’erreur si le nombre d’éléments est inférieur au nombre que vous indiquez.

Le code suivant montre le comportement et les différences entre Seq.truncate et 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

La sortie, avant que l’erreur ne se produise, est la suivante.

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

À l’aide de Seq.takeWhile, vous pouvez indiquer une fonction de prédicat (fonction booléenne) et créer une séquence à partir d’une autre séquence composée de ces éléments de la séquence d’origine pour lesquels le prédicat est true, mais l’arrêter avant le premier élément pour lequel le prédicat retourne false. Seq.skip retourne une séquence qui ignore un nombre indiqué pour les premiers éléments d’une autre séquence et retourne les éléments restants. Seq.skipWhile retourne une séquence qui ignore les premiers éléments d’une autre séquence tant que le prédicat retourne true, puis retourne les éléments restants, en commençant par le premier élément pour lequel le prédicat retourne false.

L’exemple de code suivant illustre le comportement et les différences entre Seq.takeWhile, Seq.skip et 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

La sortie est la suivante.

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

Transformation de séquences

Seq.pairwise crée une nouvelle séquence dans laquelle les éléments successifs de la séquence d’entrée sont regroupés en 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 est semblable à Seq.pairwise, sauf qu’au lieu de produire une séquence de tuples, elle produit une séquence de tableaux qui contiennent des copies d’éléments adjacents (une fenêtre) à partir de la séquence. Vous précisez le nombre d’éléments adjacents souhaités dans chaque tableau.

L'exemple de code suivant montre l'utilisation de Seq.windowed. Dans ce cas, le nombre d’éléments dans la fenêtre est 3. L’exemple utilise printSeq, qui est défini dans l’exemple de code précédent.

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

La sortie est la suivante.

Séquence initiale :

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

opérations avec plusieurs séquences

Seq.zip et Seq.zip3 prennent deux ou trois séquences et produisent une séquence de tuples. Ces fonctions sont semblables aux fonctions correspondantes disponibles pour les listes. Il n’existe aucune fonctionnalité correspondante pour séparer une séquence en deux séquences ou plus. Si vous avez besoin de cette fonctionnalité pour une séquence, convertissez la séquence en liste et utilisez List.unzip.

Tri, comparaison et regroupement

Les fonctions de tri prises en charge pour les listes fonctionnent également avec des séquences. Ces fonctions incluent Seq.sort et Seq.sortBy. Ces fonctions effectuent une itération dans l’ensemble de la séquence.

Vous comparez deux séquences à l’aide de la fonction Seq.compareWith. La fonction compare chaque élément successif à son tour et s’arrête lorsqu’elle rencontre la première paire inégale. Tous les éléments supplémentaires ne contribuent pas à la comparaison.

Le code suivant illustre l'utilisation de 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.")

Dans le code précédent, seul le premier élément est calculé et examiné, et le résultat est -1.

Seq.countBy prend une fonction qui génère une valeur appelée clé pour chaque élément. Une clé est générée pour chaque élément en appelant cette fonction sur chaque élément. Seq.countBy retourne ensuite une séquence qui contient les valeurs de clé et un nombre d’éléments ayant généré chaque valeur de la clé.

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

La sortie est la suivante.

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

La sortie précédente indique que 34 éléments de la séquence d’origine ont produit la clé 1, 33 valeurs ont produit la clé 2 et 33 valeurs ont produit la clé 0.

Vous pouvez regrouper des éléments d’une séquence en appelant Seq.groupBy. Seq.groupBy prend une séquence et une fonction qui génère une clé à partir d’un élément. La fonction est exécutée sur chaque élément de la séquence. Seq.groupBy retourne une séquence de tuples, où le premier élément de chaque tuple est la clé et le second élément est une séquence d’éléments qui produisent cette clé.

L’exemple de code suivant montre comment l’utilisation de Seq.groupBy partitionne la séquence de nombres compris entre 1 et 100 dans trois groupes avec les valeurs de clé distinctes 0, 1 et 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

La sortie est la suivante.

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

Vous pouvez créer une séquence qui élimine les éléments dupliqués en appelant Seq.distinct. Vous pouvez également utiliser Seq.distinctBy, qui prend une fonction de génération de clé pour appeler la clé sur chaque élément. La séquence qui en résulte contient des éléments de la séquence d’origine qui ont des clés uniques ; les éléments ultérieurs qui produisent une clé en double d’un élément antérieur sont ignorés.

L’exemple de code suivant illustre l’utilisation de Seq.distinct. Seq.distinct est démontré en générant des séquences qui représentent des nombres binaires, puis en montrant que les seuls éléments distincts sont 0 et 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

Le code suivant démontre Seq.distinctBy en commençant par une séquence qui contient des nombres négatifs et positifs et en utilisant la fonction de valeur absolue comme fonction de génération de clé. Il manque tous les nombres positifs qui correspondent aux nombres négatifs de la séquence, car les nombres négatifs apparaissent plus tôt dans la séquence et sont donc sélectionnés au lieu des nombres positifs qui ont la même valeur absolue ou clé.

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

Séquences en lecture seule et mises en cache

Seq.readonly crée une copie en lecture seule d’une séquence. Seq.readonly est utile lorsque vous disposez d’une collection en lecture-écriture, telle qu’un tableau, et que vous ne souhaitez pas modifier la collection d’origine. Cette fonction peut être utilisée pour conserver l’encapsulation des données. Dans l’exemple de code suivant, un type qui contient un tableau est créé. Une propriété expose le tableau, mais au lieu de retourner un tableau, elle retourne une séquence créée à partir du tableau à l’aide de 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 crée une version stockée d’une séquence. Utilisez Seq.cache pour éviter la réévaluation d’une séquence ou lorsque vous avez plusieurs threads qui utilisent une séquence, mais vous devez vous assurer que chaque élément n’est utilisé qu’une seule fois. Lorsque vous disposez d’une séquence utilisée par plusieurs threads, vous pouvez avoir un thread qui énumère et calcule les valeurs de la séquence d’origine ; les threads restants peuvent utiliser la séquence de mise en cache.

Exécution de calculs sur des séquences

Les opérations arithmétiques simples sont semblables à celles des listes, telles que Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, etc.

Seq.fold, Seq.reduce et Seq.scan sont semblables aux fonctions correspondantes disponibles pour les listes. Les séquences prennent en charge un sous-ensemble des variantes complètes de ces fonctions qui répertorient la prise en charge. Pour en savoir plus et obtenir des exemples, consultez les Listes.

Voir aussi