Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Une liste en F# est une série ordonnée et immuable d’éléments du même type. Pour effectuer des opérations de base sur des listes, utilisez les fonctions dans le module Liste.
Création et initialisation de listes
Vous pouvez définir une liste en répertoriant explicitement les éléments, séparés par des points-virgules et placés entre crochets, comme indiqué dans la ligne de code suivante.
let list123 = [ 1; 2; 3 ]
Vous pouvez également placer des sauts de ligne entre les éléments, auquel cas les points-virgules sont facultatifs. La dernière syntaxe peut entraîner un code plus lisible lorsque les expressions d’initialisation d’élément sont plus longues ou lorsque vous souhaitez inclure un commentaire pour chaque élément.
let list123 = [ 1; 2; 3 ]
Normalement, tous les éléments de liste doivent être du même type. Une exception est qu’une liste dans laquelle les éléments sont spécifiés comme étant un type de base peut avoir des éléments qui sont des types dérivés. Ainsi, les éléments suivants sont acceptables, car les deux Button et CheckBox dérivent 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 ]
Une liste vide est spécifiée par une paire de crochets sans rien entre eux.
// An empty list.
let listEmpty = []
Vous pouvez également utiliser une expression de séquence pour créer une liste. Pour plus d’informations, consultez Expressions de séquence . Par exemple, le code suivant crée une liste de carrés d’entiers compris entre 1 et 10.
let listOfSquares = [ for i in 1..10 -> i * i ]
Opérateurs pour l’utilisation de listes
Vous pouvez attacher des éléments à une liste à l’aide de l’opérateur :: (cons). Si list1 c’est [2; 3; 4]le cas, le code suivant crée list2 en tant que [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 c’est [100; 2; 3; 4][2; 3; 4] le cas, list2 ce code crée list3 en tant que [2; 3; 4; 100; 2; 3; 4].
let list3 = list1 @ list2
Les fonctions permettant d’effectuer des opérations sur des listes sont disponibles dans le module Liste.
Étant donné que les listes en F# sont immuables, toutes les opérations de modification génèrent de nouvelles listes au lieu de modifier des listes existantes.
Les listes en F# sont implémentées en tant que listes liées singly, ce qui signifie que les opérations qui accèdent uniquement à la tête 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é | Catégorie | Descriptif |
|---|---|---|
| Tête | 'T |
Premier élément. |
| Vide | 'T list |
Propriété statique qui retourne une liste vide du type approprié. |
| IsEmpty | bool |
true si la liste n’a aucun élément. |
| élément | 'T |
Élément à l’index spécifié (de base zéro). |
| Durée | int |
Nombre d’éléments. |
| Tail | 'T list |
Liste sans le premier élément. |
Voici quelques exemples d’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 qui sont importantes pour la programmation fonctionnelle.
Récursivité avec des listes
Les listes sont adaptées de manière unique aux techniques de programmation récursives. Considérez une opération qui doit être effectuée sur chaque élément d’une liste. Vous pouvez le faire de manière récursive en opérant sur la tête de la liste, puis en passant la fin de la liste, qui est une liste plus petite qui se compose de la liste d’origine sans le premier élément, de nouveau au niveau suivant de la récursivité.
Pour écrire une telle fonction récursive, vous utilisez l’opérateur cons (::) dans la correspondance de modèle, ce qui vous permet de séparer la tête d’une liste de la queue.
L’exemple de code suivant montre comment utiliser la correspondance de modèle pour implémenter une fonction récursive qui effectue 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 volumineuses, il peut dépasser la pile. Le code suivant s’améliore sur ce code à l’aide d’un argument d’accumulation, une technique standard permettant d’utiliser des fonctions récursives. L’utilisation de l’argument d’accumulation rend la fin de fonction récursive, ce qui permet d’économiser de 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 est une fonction RemoveAllMultiples récursive qui prend deux listes. La première liste contient les nombres dont les multiples seront supprimés, et la deuxième liste est la liste à partir 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, en laissant une liste de nombres premiers comme résultat.
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 principal est le plus rapide et le plus simple à accéder. 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 index, utilisez la fonction List.nth .
List.nth traverse la liste. Par conséquent, il s’agit d’O(n). Si votre code utilise List.nth fréquemment, vous pouvez envisager d’utiliser un tableau au lieu d’une liste. L’accès aux éléments dans les tableaux est O(1).
Opérations booléennes sur les listes
La fonction List.isEmpty détermine si une liste a des éléments.
La fonction List.exists applique un test booléen aux éléments d’une liste et retourne true si un élément satisfait au test.
List.exists2 est similaire, mais fonctionne sur des paires successives d’éléments 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 de 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 si vous souhaitez tester si tous les éléments d’une liste répondent à 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 dans deux listes répondent à 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 les listes
Listes de tri List.sort, List.sortBy et List.sortWith . 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 basés sur la fonction de comparaison générique pour comparer les valeurs. Il fonctionne efficacement avec un large éventail de types d’éléments, tels que des types numériques simples, des tuples, des enregistrements, des unions discriminées, des listes, des tableaux et tout type qui implémente System.IComparable. Pour les types qui implémentent System.IComparable, la comparaison générique utilise la System.IComparable.CompareTo() fonction. La comparaison générique fonctionne également avec des 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 fonction. En outre, les performances de la comparaison générique par défaut sont optimales pour les petits types structurés ; pour les types structurés plus volumineux qui doivent être comparés et triés fréquemment, envisagez d’implémenter System.IComparable et de fournir une implémentation efficace de la System.IComparable.CompareTo() méthode.
List.sortBy prend une fonction qui retourne une valeur utilisée comme critère de tri et List.sortWith prend une fonction de comparaison en tant qu’argument. Ces deux dernières fonctions sont utiles lorsque vous travaillez avec des types qui ne prennent pas en charge la comparaison, ou lorsque la comparaison nécessite une sémantique de comparaison plus complexe, comme dans le cas de chaînes prenant en charge 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 de 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 compareWidgets de comparaison personnalisée est utilisée pour comparer d’abord un champ d’un type personnalisé, puis une autre 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 les listes
De nombreuses opérations de recherche sont prises en charge pour les listes. Le plus simple, List.find, vous permet de trouver le premier élément qui correspond à une condition donnée.
L’exemple de code suivant illustre l’utilisation de List.find rechercher le premier nombre qui est 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 qui retourne une option et 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 System.Collections.Generic.KeyNotFoundException. Le code suivant montre 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 fonctions associées, retourne une valeur d’option. La List.tryFind fonction retourne le premier élément d’une liste qui satisfait à une condition si un tel élément existe, mais la valeur None d’option si ce n’est pas le cas. La variante List.tryFindIndex retourne l’index de l’élément, le cas échéant, plutôt que 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 les listes
Les opérations arithmétiques courantes telles que la somme et la moyenne sont intégrées au module Liste. Pour utiliser List.sum, le type d’élément de liste doit prendre en charge l’opérateur + et avoir une valeur nulle. Tous les types arithmétiques intégrés répondent à ces conditions. Pour utiliser 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 en tant que paramètre, et les résultats de cette fonction sont utilisés pour calculer les valeurs de la somme ou de la moyenne.
Le code suivant illustre l’utilisation de List.sum, List.sumByet 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
La sortie est 1.000000.
Le code suivant montre l’utilisation de List.averageBy.
let avg2 = List.averageBy (fun elem -> float elem) [1 .. 10]
printfn "%f" avg2
La sortie est 5.5.
Listes et Tuples
Les listes qui contiennent des tuples peuvent être manipulées par des fonctions zip et décompressées. Ces fonctions combinent deux listes de valeurs uniques en une 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 tuple. Une autre version, List.zip3, prend trois listes d’éléments uniques et produit une seule liste de tuples qui ont 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 des listes dans un tuple, où la première liste contient tous les éléments qui étaient d’abord dans chaque tuple, et la deuxième liste contient le deuxième élément 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])
Fonctionnement sur les éléments de liste
F# prend en charge diverses opérations sur les éléments de liste. Le plus simple est List.iter, qui vous permet d’appeler une fonction sur chaque élément d’une liste. Les variantes incluent List.iter2, qui vous permet d’effectuer une opération sur les éléments de deux listes, List.iteri, qui est semblable List.iter à ce que l’index de chaque élément soit passé en tant qu’argument à la fonction appelée pour chaque élément, et List.iteri2, qui est une combinaison des fonctionnalités de List.iter2 et 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 liste est List.map, qui vous permet d’appliquer une fonction à chaque élément d’une liste et de placer tous les résultats dans une nouvelle liste.
List.map2 et List.map3 sont des variantes qui prennent plusieurs listes. Vous pouvez également utiliser List.mapi et List.mapi2, si, en plus de l’élément, la fonction doit être passée à l’index de chaque élément. La seule différence entre List.mapi2 et List.mapi c’est que List.mapi2 fonctionne avec deux listes. L’exemple suivant illustre 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 semblable 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. Tous sont collectés dans une 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 qui se compose uniquement d’éléments qui répondent à 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].
Une combinaison de mappages et de filtres, 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 des éléments lorsque la fonction retourne la valeur Somed’option.
Le code suivant illustre l’utilisation de List.choose 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"]
Fonctionnement sur plusieurs listes
Les listes peuvent être jointes. Pour joindre deux listes en une seule, 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 pliage et d’analyse
Certaines opérations de liste impliquent des interdépendances entre tous les éléments de liste. Les opérations de pliage et d’analyse sont similaires List.iter et List.map dans le cas où vous appelez une fonction sur chaque élément, mais ces opérations fournissent un paramètre supplémentaire appelé l’accumulateur qui transporte des informations via le calcul.
Permet List.fold d’effectuer un calcul sur une liste.
L’exemple de code suivant illustre l’utilisation de List.fold pour effectuer différentes opérations.
La liste est parcourue ; l’accumulation acc est une valeur qui est passée le long du calcul. Le premier argument prend l’accumulateur et l’élément de liste et retourne le résultat intermédiaire du calcul de cet élément de liste. Le deuxième argument est la valeur initiale de l’accumulation.
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 qui ont un chiffre dans le nom de la fonction fonctionnent sur plusieurs listes. Par exemple, List.fold2 effectue des calculs sur deux listes.
L’exemple suivant illustre l’utilisation de 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 qui concerne la List.fold valeur finale du paramètre supplémentaire, mais List.scan retourne la liste des valeurs intermédiaires (ainsi que la valeur finale) du paramètre supplémentaire.
Chacune de ces fonctions inclut une variante inverse, par exemple , List.foldBack, qui diffère dans l’ordre dans lequel la liste est parcourue et l’ordre des arguments. En outre, List.fold et List.foldBack ont des variantes, List.fold2 et List.foldBack2, qui prennent deux listes de longueur égale. La fonction qui s’exécute sur chaque élément peut utiliser les éléments correspondants des deux listes pour effectuer 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 transaction pour un compte bancaire, et l’autre liste 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 comme la somme et List.foldList.foldBack avoir le même effet, car 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 dans une liste.
let sumListBack list = List.foldBack (fun elem acc -> 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 retourne à l’exemple de compte bancaire. Cette fois, un nouveau type de transaction est ajouté : calcul d’intérêt. Le solde de fin dépend désormais 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 est un peu semblable List.fold et List.scan, sauf que, au lieu de passer autour d’un accumulateur distinct, List.reduce prend une fonction qui prend deux arguments du type d’élément au lieu d’un seul, et l’un de ces arguments agit comme l’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’existe pas d’accumulateur distinct qui a son propre type, List.reduce ne peut être utilisé que List.fold 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 n’a aucun élément.
Dans le code suivant, le premier appel à l’expression lambda est donné aux arguments 2 et 4, et retourne 6, et l’appel suivant reçoit les arguments 6 et 10, de sorte que 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 des listes et d’autres types de collection
Le List module fournit des fonctions pour la conversion en et à partir de séquences et de tableaux. Pour effectuer une conversion vers ou depuis une séquence, utilisez List.toSeq ou List.ofSeq. Pour effectuer une conversion vers ou à partir d’un tableau, utilisez List.toArray ou List.ofArray.
Opérations supplémentaires
Pour plus d’informations sur les opérations supplémentaires sur les listes, consultez le module liste des rubriques de référence de la bibliothèque.