Partager via


Listes (F#)

En F#, une liste est une série immuable et ordonnée d'éléments du même type.

Création et initialisation de listes

Vous pouvez définir une liste en répertoriant explicitement les éléments, en les séparant par des points-virgules et en les plaçant entre crochets, comme indiqué dans la ligne de code suivante.

let list123 = [ 1; 2; 3 ]

Vous pouvez également insérer des sauts de ligne entre les éléments ; dans ce cas, les points-virgules sont facultatifs. Cette dernière syntaxe peut améliorer la lisibilité du code lorsque les expressions d'initialisation d'élément sont longues ou lorsque vous souhaitez inclure un commentaire pour chaque élément.

let list123 = [
    1
    2
    3 ]

Normalement, tous les éléments d'une liste doivent être du même type. Exception à cette règle : une liste dans laquelle il est précisé que les éléments sont d'un type de base peut contenir des éléments de types dérivés. Par conséquent, l'exemple suivant est acceptable, car Button et CheckBox dérivent tous deux de Control.

let myControlList : Control list = [ new Button(); new CheckBox() ]

Vous pouvez également définir des éléments de liste à l'aide d'une plage indiquée par des entiers séparés par l'opérateur de plage (..), comme indiqué dans le code suivant.

let list1 = [ 1 .. 10 ]

Vous pouvez également définir une liste à l'aide d'une construction de bouclage, comme dans le code suivant.

let listOfSquares = [ for i in 1 .. 10 -> i*i ]

Une liste vide est spécifiée par une paire de crochets vide.

// An empty list.
let listEmpty = []

Vous pouvez également utiliser une expression de séquence pour créer une liste. Consultez « Expressions de séquence » dans Séquences (page éventuellement en anglais). Par exemple, le code suivant crée une liste de carrés d'entiers compris entre 1 et 10.

let squaresList = [ for i in 1 .. 10 -> i * i ]

Opérateurs relatifs à l'utilisation de listes

Vous pouvez joindre des éléments à une liste à l'aide de l'opérateur (cons) ::. Si list1 contient [2; 3; 4], le code suivant crée list2 pour qu'elle contienne [100; 2; 3; 4].

let list2 = 100 :: list1

Vous pouvez concaténer des listes qui ont des types compatibles à l'aide de l'opérateur @, comme dans le code suivant. Si list1 contient [2; 3; 4] et list2 contient [100; 2; 3; 4 ], ce code crée list3 pour qu'elle contienne [2; 3; 4; 100; 2; 3; 4].

let list3 = list1 @ list2

Les fonctions permettant l'exécution d'opérations sur les listes sont disponibles dans le module List.

Parce que les listes sont immuables en F#, toute opération de modification génère de nouvelles listes plutôt que de modifier les listes existantes.

En F#, les listes sont implémentées séparément comme des listes liées, ce qui signifie que les opérations qui accèdent uniquement au début de la liste sont O(1) et que l'accès aux éléments est O(n).

Propriétés

Le type de liste prend en charge les propriétés suivantes :

Propriété

Type

Description

Head

'T

Premier élément.

Vide

'T list

Une propriété statique qui retourne une liste vide du type approprié.

IsEmpty

bool

true si la liste ne contient pas d'élément.

Élément

'T

Élément à l'index spécifié (de base zéro).

Length

int

Nombre d'éléments.

Tail

'T list

Liste sans le premier élément.

Voici quelques exemples qui illustrent l'utilisation de ces propriétés.

let list1 = [ 1; 2; 3 ]

// Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))

Utilisation de listes

La programmation avec des listes vous permet d'effectuer des opérations complexes avec une petite quantité de code. Cette section décrit les opérations courantes sur les listes, importantes en programmation fonctionnelle.

Récursivité avec des listes

Les listes sont particulièrement adaptées aux techniques de programmation récursive. Prenons l'exemple d'une opération devant être effectuée sur chaque élément d'une liste. Vous pouvez procéder de manière récursive en effectuant l'opération sur le début de la liste, puis en passant de nouveau la fin de la liste, qui est une liste plus petite comprenant la liste d'origine sans le premier élément, au niveau suivant de récursivité.

Pour écrire une telle fonction récursive, utilisez l'opérateur cons (::) dans les critères spéciaux, ce qui vous permet de séparer le début d'une liste de sa fin.

L'exemple de code suivant indique comment utiliser les critères spéciaux pour implémenter une fonction récursive qui exécute des opérations sur une liste.

let rec sum list =
   match list with
   | head :: tail -> head + sum tail
   | [] -> 0

Le code précédent fonctionne bien pour les petites listes, mais pour les listes plus grandes, il pourrait provoquer un dépassement de la pile. Le code suivant améliore le précédent en utilisant un argument d'accumulation ; technique standard pour l'utilisation de fonctions récursives. L'utilisation de l'argument d'accumulation rend la fin de la fonction récursive, ce qui permet d'économiser l'espace de pile.

let sum list =
   let rec loop list acc =
       match list with
       | head :: tail -> loop tail (acc + head)
       | [] -> acc
   loop list 0

La fonction RemoveAllMultiples est une fonction récursive qui prend deux listes. La première liste contient les nombres dont les multiples seront supprimés et la seconde liste est la liste de laquelle supprimer les nombres. Le code de l'exemple suivant utilise cette fonction récursive pour éliminer tous les nombres non premiers d'une liste, avec pour résultat une liste de nombres premiers.

let IsPrimeMultipleTest n x =
   x = n || x % n <> 0

let rec RemoveAllMultiples listn listx =
   match listn with
   | head :: tail -> RemoveAllMultiples tail (List.filter (IsPrimeMultipleTest head) listx)
   | [] -> listx


let GetPrimesUpTo n =
    let max = int (sqrt (float n))
    RemoveAllMultiples [ 2 .. max ] [ 1 .. n ]

printfn "Primes Up To %d:\n %A" 100 (GetPrimesUpTo 100)

La sortie est la suivante :

Primes Up To 100:
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; 73; 79; 83; 89; 97]

Fonctions de module

Le module List fournit des fonctions qui accèdent aux éléments d'une liste. L'élément head est celui dont l'accès est le plus simple et le plus rapide. Utilisez la propriété Head ou la fonction de module List.head. Vous pouvez accéder à la fin d'une liste à l'aide de la propriété Tail ou de la fonction List.tail. Pour rechercher un élément par son index, utilisez la fonction List.nth. List.nth parcourt la liste. Par conséquent, il s'agit d'O(n). Si votre code utilise fréquemment List.nth, vous pourriez envisager d'utiliser un tableau au lieu d'une liste. L'accès aux éléments des tableaux est O(1).

Opérations booléennes sur des listes

La fonction List.isEmpty détermine si une liste contient des éléments.

La fonction List.exists applique un test booléen aux éléments d'une liste et retourne la valeur true si un élément satisfait au test. La fonction List.exists2 est semblable, mais fonctionne sur des paires d'éléments consécutives dans deux listes.

Le code suivant illustre l'utilisation de List.exists.

// Use List.exists to determine whether there is an element of a list satisfies a given Boolean expression.
// containsNumber returns true if any of the elements of the supplied list match 
// the supplied number.
let containsNumber number list = List.exists (fun elem -> elem = number) list
let list0to3 = [0 .. 3]
printfn "For list %A, contains zero is %b" list0to3 (containsNumber 0 list0to3)

La sortie est la suivante :

For list [0; 1; 2; 3], contains zero is true

L'exemple suivant illustre l'utilisation du mot clé List.exists2 :

// Use List.exists2 to compare elements in two lists.
// isEqualElement returns true if any elements at the same position in two supplied
// lists match.
let isEqualElement list1 list2 = List.exists2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
let list1to5 = [ 1 .. 5 ]
let list5to1 = [ 5 .. -1 .. 1 ]
if (isEqualElement list1to5 list5to1) then
    printfn "Lists %A and %A have at least one equal element at the same position." list1to5 list5to1
else
    printfn "Lists %A and %A do not have an equal element at the same position." list1to5 list5to1

La sortie est la suivante :

Lists [1; 2; 3; 4; 5] and [5; 4; 3; 2; 1] have at least one equal element at the same position.

Vous pouvez utiliser List.forall pour tester si tous les éléments d'une liste satisfont à une condition.

let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list
printfn "%b" (isAllZeroes [0.0; 0.0])
printfn "%b" (isAllZeroes [0.0; 1.0])

La sortie est la suivante :

true
false

De même, List.forall2 détermine si tous les éléments des positions correspondantes de deux listes satisfont à une expression booléenne qui implique chaque paire d'éléments.

let listEqual list1 list2 = List.forall2 (fun elem1 elem2 -> elem1 = elem2) list1 list2
printfn "%b" (listEqual [0; 1; 2] [0; 1; 2])
printfn "%b" (listEqual [0; 0; 0] [0; 1; 0])

La sortie est la suivante :

true
false

Opérations de tri sur des listes

Les fonctions List.sort, List.sortBy et List.sortWith trient les listes. La fonction de tri détermine laquelle de ces trois fonctions utiliser. List.sort utilise la comparaison générique par défaut. La comparaison générique utilise des opérateurs globaux reposant sur la fonction de comparaison générique pour comparer des valeurs. Elle fonctionne efficacement avec une large gamme de types d'éléments, tels que les types numériques simples, les tuples, les enregistrements, les unions discriminées, les listes, les tableaux et tout type qui implémente IComparable. Pour les types qui implémentent IComparable, la comparaison générique utilise la fonction CompareTo. La comparaison générique fonctionne également avec les chaînes, mais utilise un ordre de tri indépendant de la culture. La comparaison générique ne doit pas être utilisée sur les types non pris en charge, tels que les types de fonctions. De même, les performances de la comparaison générique par défaut sont meilleures pour les petits types structurés ; pour les types structurés plus grands qui demandent à être comparés et triés fréquemment, envisagez l'implémentation de IComparable et la mise en œuvre d'une implémentation efficace de la méthode CompareTo.

List.sortBy prend une fonction qui retourne une valeur utilisée comme critère de tri et List.sortWith prend une fonction de comparaison comme argument. Ces deux fonctions sont utiles lorsque vous travaillez avec des types qui ne prennent pas en charge la comparaison ou lorsque la comparaison requiert une sémantique de comparaison plus complexe, comme dans le cas de chaînes qui prennent en compte la culture.

L'exemple suivant illustre l'utilisation de List.sort.

let sortedList1 = List.sort [1; 4; 8; -2; 5]
printfn "%A" sortedList1

La sortie est la suivante :

[-2; 1; 4; 5; 8]

L'exemple suivant illustre l'utilisation du mot clé List.sortBy.

let sortedList2 = List.sortBy (fun elem -> abs elem) [1; 4; 8; -2; 5]
printfn "%A" sortedList2

La sortie est la suivante :

[1; -2; 4; 5; 8]

L'exemple suivant illustre l'utilisation de List.sortWith. Dans cet exemple, la fonction de comparaison personnalisée compareWidgets est utilisée pour comparer d'abord un champ d'un type personnalisé, puis un autre champ lorsque les valeurs du premier champ sont égales.

type Widget = { ID: int; Rev: int }

let compareWidgets widget1 widget2 =
   if widget1.ID < widget2.ID then -1 else
   if widget1.ID > widget2.ID then 1 else
   if widget1.Rev < widget2.Rev then -1 else
   if widget1.Rev > widget2.Rev then 1 else
   0

let listToCompare = [
    { ID = 92; Rev = 1 }
    { ID = 110; Rev = 1 }
    { ID = 100; Rev = 5 }
    { ID = 100; Rev = 2 }
    { ID = 92; Rev = 1 }
    ]

let sortedWidgetList = List.sortWith compareWidgets listToCompare
printfn "%A" sortedWidgetList

La sortie est la suivante :

  [{ID = 92;
    Rev = 1;}; {ID = 92;
                Rev = 1;}; {ID = 100;
                            Rev = 2;}; {ID = 100;
                                        Rev = 5;}; {ID = 110;
                                                    Rev = 1;}]

Opérations de recherche sur des listes

Plusieurs opérations de recherche sont prises en charge pour les listes. La plus simple, List.find, vous permet de rechercher le premier élément qui correspond à une condition donnée.

L'exemple de code suivant illustre l'utilisation de List.find pour rechercher le premier nombre divisible par 5 dans une liste.

let isDivisibleBy number elem = elem % number = 0
let result = List.find (isDivisibleBy 5) [ 1 .. 100 ]
printfn "%d " result

Le résultat est 5.

Si les éléments doivent être transformés en premier, appelez List.pick, qui prend une fonction retournant une option, puis recherche la première valeur d'option qui est Some(x). Au lieu de retourner l'élément, List.pick retourne le résultat x. Si aucun élément correspondant n'est trouvé, List.pick lève KeyNotFoundException. Le code suivant illustre l'utilisation de List.pick.

let valuesList = [ ("a", 1); ("b", 2); ("c", 3) ]

let resultPick = List.pick (fun elem ->
                    match elem with
                    | (value, 2) -> Some value
                    | _ -> None) valuesList
printfn "%A" resultPick

La sortie est la suivante :

"b"

Un autre groupe d'opérations de recherche, List.tryFind et les fonctions connexes, génère une valeur d'option. La fonction List.tryFind retourne le premier élément d'une liste qui satisfait à une condition, s'il existe, et la valeur d'option None dans le cas contraire. La variation List.tryFindIndex retourne l'index de l'élément, le cas échéant, et non l'élément lui-même. Ces fonctions sont illustrées dans le code suivant.

let list1d = [1; 3; 7; 9; 11; 13; 15; 19; 22; 29; 36]
let isEven x = x % 2 = 0
match List.tryFind isEven list1d with
| Some value -> printfn "The first even value is %d." value
| None -> printfn "There is no even value in the list."

match List.tryFindIndex isEven list1d with
| Some value -> printfn "The first even value is at position %d." value
| None -> printfn "There is no even value in the list."

La sortie est la suivante :

The first even value is 22.
The first even value is at position 8.

Opérations arithmétiques sur des listes

Des opérations arithmétiques courantes telles que la somme et la moyenne sont intégrées au module List. Pour fonctionner avec List.sum, le type d'élément de liste doit prendre en charge l'opérateur + et avoir une valeur égale à zéro. Tous les types arithmétiques intégrés satisfont à ces conditions. Pour fonctionner avec List.average, le type d'élément doit prendre en charge la division sans reste, ce qui exclut les types intégraux, mais autorise les types à virgule flottante. Les fonctions List.sumBy et List.averageBy prennent une fonction comme paramètre, et les résultats de cette fonction sont utilisés pour calculer les valeurs pour la somme ou la moyenne.

Le code suivant illustre l'utilisation de List.sum, de List.sumBy et de List.average.

// Compute the sum of the first 10 integers by using List.sum.
let sum1 = List.sum [1 .. 10]

// Compute the sum of the squares of the elements of a list by using List.sumBy.
let sum2 = List.sumBy (fun elem -> elem*elem) [1 .. 10]

// Compute the average of the elements of a list by using List.average.
let avg1 = List.average [0.0; 1.0; 1.0; 2.0]

printfn "%f" avg1

Le résultat est 1.000000.

Le code suivant illustre l'utilisation de List.averageBy.

let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2

Le résultat est 5.5.

Listes et tuples

Les listes qui contiennent des tuples peuvent être manipulées par des fonctions de compression et de décompression. Ces fonctions combinent deux listes de valeurs uniques en une seule liste de tuples ou séparent une liste de tuples en deux listes de valeurs uniques. La fonction List.zip la plus simple prend deux listes d'éléments uniques et produit une liste unique de paires de tuples. Une autre version, List.zip3, prend trois listes d'éléments uniques et produit une liste unique de tuples ayant trois éléments. L'exemple de code suivant illustre l'utilisation de List.zip.

let list1 = [ 1; 2; 3 ]
let list2 = [ -1; -2; -3 ]
let listZip = List.zip list1 list2
printfn "%A" listZip

La sortie est la suivante :

[(1, -1); (2, -2); (3; -3)]

L'exemple de code suivant illustre l'utilisation de List.zip3.

let list3 = [ 0; 0; 0]
let listZip3 = List.zip3 list1 list2 list3
printfn "%A" listZip3

La sortie est la suivante :

[(1, -1, 0); (2, -2, 0); (3, -3, 0)]

Les versions de décompression correspondantes, List.unzip et List.unzip3, prennent des listes de tuples et retournent les listes dans un tuple, où la première liste contient tous les premiers éléments de chaque tuple, la deuxième liste les deuxièmes éléments de chaque tuple, et ainsi de suite.

L'exemple de code suivant illustre l'utilisation de List.unzip.

let lists = List.unzip [(1,2); (3,4)]
printfn "%A" lists
printfn "%A %A" (fst lists) (snd lists)

La sortie est la suivante :

([1; 3], [2; 4])
[1; 3] [2; 4]

L'exemple de code suivant illustre l'utilisation de List.unzip3.

let listsUnzip3 = List.unzip3 [(1,2,3); (4,5,6)]
printfn "%A" listsUnzip3

La sortie est la suivante :

([1; 4], [2; 5], [3; 6])

Opérations sur des éléments de liste

F# prend en charge un large éventail d'opérations sur des éléments de liste. L'opération la plus simple, List.iter, vous permet d'appeler une fonction sur chaque élément d'une liste. Ses variations incluent List.iter2, qui vous permet d'exécuter une opération sur les éléments de deux listes, List.iteri, qui est semblable à List.iter, sauf que l'index de chaque élément est passé comme argument à la fonction appelée pour chaque élément, et List.iteri2, qui est une combinaison des fonctionnalités de List.iter2 et de List.iteri. L'exemple de code suivant illustre ces fonctions.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
List.iter (fun x -> printfn "List.iter: element is %d" x) list1
List.iteri(fun i x -> printfn "List.iteri: element %d is %d" i x) list1
List.iter2 (fun x y -> printfn "List.iter2: elements are %d %d" x y) list1 list2
List.iteri2 (fun i x y ->
               printfn "List.iteri2: element %d of list1 is %d element %d of list2 is %d"
                 i x i y)
            list1 list2

La sortie est la suivante :

List.iter: element is 1
List.iter: element is 2
List.iter: element is 3
List.iteri: element 0 is 1
List.iteri: element 1 is 2
List.iteri: element 2 is 3
List.iter2: elements are 1 4
List.iter2: elements are 2 5
List.iter2: elements are 3 6
List.iteri2: element 0 of list1 is 1; element 0 of list2 is 4
List.iteri2: element 1 of list1 is 2; element 1 of list2 is 5
List.iteri2: element 2 of list1 is 3; element 2 of list2 is 6

Une autre fonction fréquemment utilisée, qui transforme les éléments de listes, est List.map, qui vous permet d'appliquer une fonction à chaque élément d'une liste et de mettre tous les résultats dans une nouvelle liste. List.map2 et List.map3 sont des variations qui prennent plusieurs listes. Vous pouvez également utiliser List.mapi et List.mapi2, si, en plus de l'élément, l'index de chaque élément doit être passé à la fonction. La seule différence entre List.mapi2 et List.mapi est que List.mapi2 fonctionne avec deux listes. L'exemple suivant illustre le fonctionnement de List.map.

let list1 = [1; 2; 3]
let newList = List.map (fun x -> x + 1) list1
printfn "%A" newList

La sortie est la suivante :

[2; 3; 4]

L'exemple suivant illustre l'utilisation de List.map2.

let list1 = [1; 2; 3]
let list2 = [4; 5; 6]
let sumList = List.map2 (fun x y -> x + y) list1 list2
printfn "%A" sumList

La sortie est la suivante :

[5; 7; 9]

L'exemple suivant illustre l'utilisation de List.map3.

let newList2 = List.map3 (fun x y z -> x + y + z) list1 list2 [2; 3; 4]
printfn "%A" newList2

La sortie est la suivante :

[7; 10; 13]

L'exemple suivant illustre l'utilisation de List.mapi.

let newListAddIndex = List.mapi (fun i x -> x + i) list1
printfn "%A" newListAddIndex

La sortie est la suivante :

[1; 3; 5]

L'exemple suivant illustre l'utilisation de List.mapi2.

let listAddTimesIndex = List.mapi2 (fun i x y -> (x + y) * i) list1 list2
printfn "%A" listAddTimesIndex

La sortie est la suivante :

[0; 7; 18]

List.collect est comme List.map, sauf que chaque élément produit une liste et que toutes ces listes sont concaténées dans une liste finale. Dans le code suivant, chaque élément de la liste génère trois nombres. Ces nombres sont tous réunis dans une seule liste.

let collectList = List.collect (fun x -> [for i in 1..3 -> x * i]) list1
printfn "%A" collectList

La sortie est la suivante :

[1; 2; 3; 2; 4; 6; 3; 6; 9]

Vous pouvez également utiliser List.filter, qui prend une condition booléenne et produit une nouvelle liste composée uniquement des éléments qui satisfont à la condition donnée.

let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]

La liste résultante est [2; 4; 6].

Combinaison des opérations de mappage et de filtre, List.choose vous permet de transformer et de sélectionner des éléments en même temps. List.choose applique une fonction qui retourne une option à chaque élément d'une liste et retourne une nouvelle liste des résultats pour les éléments lorsque la fonction retourne la valeur d'option Some.

Le code suivant illustre l'utilisation de List.choose pour sélectionner des mots en majuscules dans une liste de mots.

let listWords = [ "and"; "Rome"; "Bob"; "apple"; "zebra" ]
let isCapitalized (string1:string) = System.Char.IsUpper string1.[0]
let results = List.choose (fun elem ->
    match elem with
    | elem when isCapitalized elem -> Some(elem + "'s")
    | _ -> None) listWords
printfn "%A" results

La sortie est la suivante :

["Rome's"; "Bob's"]

Opérations sur plusieurs listes

Les listes peuvent être jointes. Pour joindre deux listes, utilisez List.append. Pour joindre plus de deux listes, utilisez List.concat.

let list1to10 = List.append [1; 2; 3] [4; 5; 6; 7; 8; 9; 10]
let listResult = List.concat [ [1; 2; 3]; [4; 5; 6]; [7; 8; 9] ]
List.iter (fun elem -> printf "%d " elem) list1to10
printfn ""
List.iter (fun elem -> printf "%d " elem) listResult

Opérations de repli et d'analyse

Certaines opérations impliquent l'interdépendance entre tous les éléments de la liste. Les opérations d'analyse et de repli sont semblables à List.iter et List.map, en ce sens que vous appelez une fonction sur chaque élément. Toutefois, ces opérations fournissent un paramètre supplémentaire, appelé accumulateur, qui achemine des informations par l'intermédiaire du calcul.

Utilisez List.fold pour exécuter un calcul sur une liste.

L'exemple de code suivant illustre l'utilisation de List.fold pour exécuter différentes opérations.

La liste est parcourue ; l'accumulateur acc est une valeur passée tandis que le calcul s'effectue. Le premier argument prend l'accumulateur et l'élément de liste, puis retourne le résultat intermédiaire du calcul pour cet élément de liste. Le deuxième argument est la valeur initiale de l'accumulateur.

let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 3 ] (sumList [ 1 .. 3 ])

// The following example computes the average of a list.
let averageList list = (List.fold (fun acc elem -> acc + float elem) 0.0 list / float list.Length)

// The following example computes the standard deviation of a list.
// The standard deviation is computed by taking the square root of the
// sum of the variances, which are the differences between each value
// and the average.
let stdDevList list =
    let avg = averageList list
    sqrt (List.fold (fun acc elem -> acc + (float elem - avg) ** 2.0 ) 0.0 list / float list.Length)

let testList listTest =
    printfn "List %A average: %f stddev: %f" listTest (averageList listTest) (stdDevList listTest)

testList [1; 1; 1]
testList [1; 2; 1]
testList [1; 2; 3]

// List.fold is the same as to List.iter when the accumulator is not used.
let printList list = List.fold (fun acc elem -> printfn "%A" elem) () list
printList [0.0; 1.0; 2.5; 5.1 ]

// The following example uses List.fold to reverse a list.
// The accumulator starts out as the empty list, and the function uses the cons operator
// to add each successive element to the head of the accumulator list, resulting in a
// reversed form of the list.
let reverseList list = List.fold (fun acc elem -> elem::acc) [] list
printfn "%A" (reverseList [1 .. 10])

Les versions de ces fonctions (contenant un chiffre dans le nom de fonction) fonctionnent sur plusieurs listes. Par exemple, List.fold2 exécute des calculs sur deux listes.

L'exemple suivant illustre l'utilisation du mot clé List.fold2 :

// Use List.fold2 to perform computations over two lists (of equal size) at the same time.
// Example: Sum the greater element at each list position.
let sumGreatest list1 list2 = List.fold2 (fun acc elem1 elem2 ->
                                              acc + max elem1 elem2) 0 list1 list2

let sum = sumGreatest [1; 2; 3] [3; 2; 1]
printfn "The sum of the greater of each pair of elements in the two lists is %d." sum

List.fold et List.scan diffèrent en ce que List.fold retourne la valeur finale du paramètre supplémentaire, tandis que List.scan retourne la liste des valeurs intermédiaires (avec la valeur finale) du paramètre supplémentaire.

Chacune de ces fonctions inclut une variation inverse, par exemple List.foldBack, qui diffère au niveau de l'ordre dans lequel la liste est parcourue et au niveau de l'ordre des arguments. De même, List.fold et List.foldBack ont des variations : List.fold2 et List.foldBack2, qui prennent deux listes de longueur égale. La fonction qui s'exécute sur chaque élément peut utiliser des éléments correspondants des deux listes pour exécuter une action. Les types d'éléments des deux listes peuvent être différents, comme dans l'exemple suivant, dans lequel une liste contient des montants de transactions pour un compte bancaire et l'autre contient le type de transaction : dépôt ou retrait.

// Discriminated union type that encodes the transaction type.
type Transaction =
    | Deposit
    | Withdrawal

let transactionTypes = [Deposit; Deposit; Withdrawal]
let transactionAmounts = [100.00; 1000.00; 95.00 ]
let initialBalance = 200.00

// Use fold2 to perform a calculation on the list to update the account balance.
let endingBalance = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2)
                                initialBalance
                                transactionTypes
                                transactionAmounts
printfn "%f" endingBalance

Pour un calcul tel qu'une addition, List.fold et List.foldBack ont le même effet parce que le résultat ne dépend pas de l'ordre de traversée. Dans l'exemple suivant, List.foldBack est utilisé pour ajouter les éléments à une liste.

let sumListBack list = List.foldBack (fun acc elem -> acc + elem) list 0
printfn "%d" (sumListBack [1; 2; 3])

// For a calculation in which the order of traversal is important, fold and foldBack have different
// results. For example, replacing fold with foldBack in the listReverse function
// produces a function that copies the list, rather than reversing it.
let copyList list = List.foldBack (fun elem acc -> elem::acc) list []
printfn "%A" (copyList [1 .. 10])

L'exemple suivant reprend l'exemple du compte bancaire. Cette fois, un nouveau type de transaction est ajouté : calcul d'intérêts. Le solde de fin dépend maintenant de l'ordre des transactions.

type Transaction2 =
    | Deposit
    | Withdrawal
    | Interest

let transactionTypes2 = [Deposit; Deposit; Withdrawal; Interest]
let transactionAmounts2 = [100.00; 1000.00; 95.00; 0.05 / 12.0 ]
let initialBalance2 = 200.00

// Because fold2 processes the lists by starting at the head element,
// the interest is calculated last, on the balance of 1205.00.
let endingBalance2 = List.fold2 (fun acc elem1 elem2 ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                initialBalance2
                                transactionTypes2
                                transactionAmounts2
printfn "%f" endingBalance2
// Because foldBack2 processes the lists by starting at end of the list,
// the interest is calculated first, on the balance of only 200.00.
let endingBalance3 = List.foldBack2 (fun elem1 elem2 acc ->
                                match elem1 with
                                | Deposit -> acc + elem2
                                | Withdrawal -> acc - elem2
                                | Interest -> acc * (1.0 + elem2))
                                transactionTypes2
                                transactionAmounts2
                                initialBalance2
printfn "%f" endingBalance3

La fonction List.reduce ressemble quelque peu à List.fold et List.scan, mais au lieu de faire passer un accumulateur séparé, List.reduce prend une fonction qui prend deux arguments du type d'élément au lieu d'un et l'un de ces arguments joue le rôle d'accumulateur, ce qui signifie qu'il stocke le résultat intermédiaire du calcul. List.reduce commence par fonctionner sur les deux premiers éléments de liste, puis utilise le résultat de l'opération avec l'élément suivant. Étant donné qu'il n'y a pas d'accumulateur séparé qui possède son propre type, List.reduce ne peut être utilisée à la place de List.fold que lorsque l'accumulateur et le type d'élément ont le même type. Le code suivant illustre l'utilisation de List.reduce. List.reduce lève une exception si la liste fournie ne contient pas d'élément.

Dans le code suivant, le premier appel à l'expression lambda reçoit les arguments 2 et 4, et retourne 6 ; l'appel suivant reçoit les arguments 6 et 10, donc le résultat est 16.

let sumAList list =
    try
        List.reduce (fun acc elem -> acc + elem) list
    with
       | :? System.ArgumentException as exc -> 0

let resultSum = sumAList [2; 4; 10]
printfn "%d " resultSum

Conversion entre listes et autres types de collections

Le module List fournit des fonctions pour la conversion vers et depuis des séquences et des tableaux. Pour convertir vers ou depuis une séquence, utilisez List.toSeq ou List.ofSeq. Pour convertir vers ou depuis un tableau, utilisez List.toArray ou List.ofArray.

Opérations supplémentaires

Pour plus d'informations sur d'autres opérations sur les listes, consultez la rubrique de référence de la bibliothèque Collections.List, module (F#).

Voir aussi

Référence

Séquences (F#)

Options (F#)

Autres ressources

Référence du langage F#

Types F#

Tableaux (F#)

Historique des modifications

Date

Historique

Motif

Octobre 2010

La sortie d'un des exemples de code a été corrigée

Commentaires client.

Avril 2011

Les informations sur la propriété Empty dans la section Propriétés ont été corrigées.

Commentaires client.