Partager via


Séquences (F#)

Une séquence est une série logique d'éléments d'un même type. Les séquences sont particulièrement utiles lorsque vous avez une vaste collection ordonnée de données, mais que vous ne pensez pas nécessairement utiliser tous les éléments. Les éléments de séquence individuels sont calculés uniquement lorsque cela est nécessaire. Par conséquent, une séquence peut fournir de meilleures performances qu'une liste dans les situations dans lesquelles 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. Par conséquent, tout type .NET Framework qui implémente System.IEnumerable peut être utilisé comme une séquence. Le module Seq fournit la prise en charge des manipulations qui impliquent des séquences.

Expressions de séquence

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

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

Les expressions de séquence sont composées d'expressions F# qui produisent les valeurs de la séquence. Elles peuvent utiliser le mot clé yield pour produire les valeurs qui feront partie de la séquence.

Voici un exemple.

seq { for i in 1 .. 10 do yield i * i }

Vous pouvez utiliser l'opérateur -> au lieu de yield, auquel cas vous pouvez omettre le mot clé do, comme indiqué dans l'exemple suivant.

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

Le code suivant génère une liste de paires de coordonnées et un index dans un tableau qui représente la grille.

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

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 ayez une fonction isprime de type int -> bool, construisez la séquence comme suit.

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

Lorsque vous utilisez yield ou -> dans une itération, chaque itération est censée générer un élément unique de la séquence. Si chaque itération produit une séquence d'éléments, utilisez yield!. Dans ce cas, les éléments générés sur chaque itération sont concaténés pour produire la séquence finale.

Vous pouvez combiner plusieurs expressions dans une expression de séquence. Les éléments générés par chaque expression sont concaténés ensemble. Pour obtenir un exemple, consultez la section « Exemples » de cette rubrique.

Exemples

Le premier exemple utilise une expression de séquence qui contient une itération, un filtre et une instruction yield pour générer un tableau. Ce code imprime une séquence de nombres premiers de 1 à 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 yield n }
for x in aSequence do
    printfn "%d" x

Le code suivant utilise l'instruction yield pour créer une table de multiplication qui se compose de tuples de trois éléments, chacun d'entre eux comprenant deux facteurs et le produit.

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

L'exemple suivant illustre l'utilisation de yield! pour combiner des séquences individuelles en une séquence finale unique. Dans ce cas, les séquences de chaque sous-arborescence dans une arborescence binaire sont concaténées dans 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 bon nombre des mêmes fonctions que les listes. Les séquences prennent également en charge des opérations telles que le regroupement et le décompte à l'aide des fonctions génératrices de clé. Les séquences prennent également en charge des fonctions plus diverses pour l'extraction de sous-séquences.

De nombreux types de données, tels que les listes, les tableaux, les jeux et les mappages sont implicitement des séquences, car ils sont des collections énumérables. Une fonction qui prend une séquence comme un argument fonctionne avec chacun des types de données F# courants, en plus de tout type de données .NET Framework qui implémente IEnumerable. Opposez à ceci une fonction qui prend une liste comme un argument, qui ne peut prendre que des listes. Le type seq<'a> est une abréviation de type pour IEnumerable<'a>. Cela signifie que tout type qui implémente l'IEnumerable générique, qui inclut des tableaux, des listes, des jeux et des mappages en F#, et également la plupart des types de collection .NET Framework, 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 Microsoft.FSharp.Collections contient des fonctions pour l'utilisation de séquences. Ces fonctions opèrent également avec les listes, les tableaux, les mappages et les jeux, parce que tous ces types sont énumérables et, par conséquent, peuvent ê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 en utilisant 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 pour laquelle 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 comme List.init, sauf que les éléments ne sont pas créés tant que vous n'itérez pas au sein de 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

Le résultat est le suivant :

0 10 20 30 40

En utilisant Seq.ofArray et Seq.ofList<'T>, fonction (F#), 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 illustré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

En utilisant Seq.cast, vous pouvez créer une séquence à partir d'une collection faiblement typée, comme celles définies dans System.Collections. Ces collections faiblement typées ont le type d'élément Object et sont énumérées à l'aide du type IEnumerable non générique. Le code suivant illustre l'utilisation de Seq.cast pour convertir une ArrayList en séquence.

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

Vous pouvez définir des séquences infinies à l'aide de la fonction Seq.initInfinite. Pour une telle 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 grâce à l'évaluation tardive ; les éléments sont créés lorsque cela est nécessaire, en appelant la fonction que vous spécifiez. L'exemple de code suivant produit une séquence infinie de nombres à virgule flottante ; dans ce cas, la série alternante de réciproques de carrés d'entiers consécutifs.

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 de la séquence. L'état est juste une valeur utilisée pour calculer chaque élément, et peut changer tandis 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 présente deux exemples de séquences, seq1 et fib, générées par une opération unfold. La première, seq1, est juste une séquence simple avec des nombres jusqu'à 100. La seconde, fib, utilise unfold pour calculer la séquence de Fibonacci. Étant donné que chaque élément de la séquence de Fibonacci est la somme des deux nombres de Fibonacci précédents, la valeur d'état est un tuple qui se compose des deux nombres précédents de la séquence. La valeur initiale est (1,1), les deux premiers nombres de la séquence.

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

La sortie est la suivante :

La séquence seq1 contient les numéros de 0 à 20.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Le fib de séquence contient les nombres Fibonacci.

2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

Le code suivant est un exemple qui utilise bon nombre des fonctions du module de séquence décrites ici pour générer et calculer les valeurs de séquences infinies. Le code peut prendre quelques minutes pour s'exécuter.

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

Recherche d'éléments

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

Obtention de sous-séquences

Seq.filter et Seq.choose sont comme les fonctions correspondantes qui sont disponibles pour les listes, sauf que le filtrage et le choix ne se produisent pas tant que les éléments de séquence n'ont pas été évalués.

Seq.truncate crée une séquence à partir d'une autre séquence, mais limite la séquence à un nombre spécifié d'éléments. Seq.take crée une séquence qui contient uniquement un nombre spécifié d'éléments à partir du début d'une séquence. S'il y a moins d'éléments dans la séquence que vous ne spécifiez d'en prendre, Seq.take lève une InvalidOperationException. La différence entre Seq.take et Seq.truncate est que Seq.truncate ne produit pas d'erreur si le nombre d'éléments est inférieur au nombre que vous spécifiez.

Le code suivant présente le comportement de Seq.truncate et de Seq.take et leurs différences.

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 comme suit.

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

En utilisant Seq.takeWhile, vous pouvez spécifier une fonction de prédicat (fonction booléenne) et créer une séquence à partir d'une autre séquence composée des éléments de la séquence d'origine pour lesquels le prédicat est true, mais arrêter avant le premier élément pour lequel le prédicat retourne la valeur false. Seq.skip retourne une séquence qui ignore un nombre spécifié des 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 la valeur true, puis retourne les éléments restants, en commençant par le premier élément pour lequel le prédicat retourne la valeur false.

L'exemple de code suivant illustre le comportement de Seq.takeWhile, de Seq.skip et de Seq.skipWhile, et leurs différences.

// 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 séquence dans laquelle les éléments consécutifs de la séquence d'entrée sont regroupés dans des 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 comme Seq.pairwise, mais au lieu de produire une séquence de tuples, elle produit une séquence de tableaux qui contiennent des copies d'éléments adjacents (fenêtre) de la séquence. Vous spécifiez le nombre d'éléments adjacents que vous souhaitez dans chaque tableau.

L'exemple de code suivant illustre l'utilisation de Seq.windowed. Dans ce cas, le nombre d'éléments dans la fenêtre est de 3. L'exemple utilise printSeq, 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 d'origine :

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 comme les fonctions correspondantes disponibles pour les listes. Il n'existe pas de 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 en liste et utilisez List.unzip.

Tri, comparaison et regroupement

Les fonctions de tri prises en charge pour les listes fonctionnent également avec les séquences. Cela inclut Seq.sort et Seq.sortBy. Ces fonctions itèrent au sein de la séquence entière.

Vous pouvez comparer deux séquences à l'aide de la fonction Seq.compareWith. La fonction compare les éléments consécutifs tour à tour, puis s'arrête lorsqu'elle rencontre la première paire inégale. Tout élément supplémentaire n'est pas pris en compte pour 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 des clés, et le 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; printfn "" 
let seqResult = Seq.countBy (fun elem -> if elem % 3 = 0 then 0
                                         elif elem % 3 = 1 then 1
                                         else 2) mySeq1

printSeq seqResult

La sortie est la suivante.

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

La sortie précédente présente 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 les é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 est une séquence d'éléments qui produisent la clé.

L'exemple de code suivant illustre l'utilisation de Seq.groupBy pour partitionner la séquence de nombres de 1 à 100 en trois groupes qui ont les valeurs de clés 0, 1 et 2 distinctes.

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

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 des éléments en double en appelant Seq.distinct. Sinon, vous pouvez utiliser Seq.distinctBy, qui prend une fonction génératrice de clé à appeler sur chaque élément. La séquence résultante contient les é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 illustrée 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 illustre 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 génératrice de clé. La séquence résultante omet tous les nombres positifs qui correspondent aux nombres négatifs de la séquence, parce que les nombres négatifs apparaissent plus tôt dans la séquence et, par conséquent, sont sélectionnés à la place 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 ""
printfn "Original sequence: "
printSeq inputSequence
printfn "\nSequence with distinct absolute values: " 
let seqDistinctAbsoluteValue = Seq.distinctBy (fun elem -> abs elem) inputSequence
seqDistinctAbsoluteValue |> printSeq

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 avez 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 de 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 que vous devez vous assurer que chaque élément n'est traité qu'une seule fois. Lorsque vous avez une séquence utilisée par plusieurs threads, vous pouvez avoir un thread qui énumère et calcule les valeurs pour la séquence d'origine, et les autres threads qui utilisent la séquence mise en cache.

Exécution de calculs sur les séquences

Les opérations arithmétiques simples sont comme celles des listes, telles que Seq.average, Seq.sum, Seq.averageBy, Seq.sumBy, et ainsi de suite.

Seq.fold, Seq.reduce et Seq.scan sont comme les fonctions correspondantes qui sont disponibles pour les listes. Les séquences prennent en charge un sous-ensemble des variations complètes des fonctions prises en charge par les listes. Pour plus d'informations et d'exemples, consultez Listes (F#).

Voir aussi

Référence

IEnumerable

Autres ressources

Référence du langage F#

Types F#