Elm Language
Listes et itération
Recherche…
Remarques
La List ( liste liée ) brille en accès séquentiel :
- accéder au premier élément
- précédant le début de la liste
- effacer de la liste
D'un autre côté, ce n'est pas idéal pour un accès aléatoire (c.-à-d. Obtenir le nième élément) et la traversée dans l'ordre inverse , et vous pourriez avoir plus de chance (et de performances) avec la structure de données Array .
Créer une liste par plage
Avant 0.18.0, vous pouvez créer des plages comme ceci:
> range = [1..5]
[1,2,3,4,5] : List number
>
> negative = [-5..3]
[-5,-4,-3,-2,-1,0,1,2,3] : List number
Dans 0.18.0 La syntaxe [1..5] a été supprimée .
> range = List.range 1 5
[1,2,3,4,5] : List number
>
> negative = List.range -5 3
[-5,-4,-3,-2,-1,0,1,2,3] : List number
Les plages créées par cette syntaxe sont toujours inclusives et le pas est toujours 1 .
Créer une liste
> listOfNumbers = [1,4,99]
[1,4,99] : List number
>
> listOfStrings = ["Hello","World"]
["Hello","World"] : List String
>
> emptyList = [] -- can be anything, we don't know yet
[] : List a
>
Sous le capot, List ( liste chaînée ) est construit par la fonction :: (appelée "cons"), qui prend deux arguments: un élément, appelé tête, et une liste (éventuellement vide) à laquelle la tête est ajoutée.
> withoutSyntaxSugar = 1 :: []
[1] : List number
>
> longerOne = 1 :: 2 :: 3 :: []
[1,2,3] : List number
>
> nonemptyTail = 1 :: [2]
[1,2] : List number
>
List ne peut prendre que des valeurs d'un type, donc quelque chose comme [1,"abc"] n'est pas possible. Si vous en avez besoin, utilisez des tuples.
> notAllowed = [1,"abc"]
==================================== ERRORS ====================================
-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
The 1st and 2nd elements are different types of values.
8| [1,"abc"]
^^^^^
The 1st element has this type:
number
But the 2nd is:
String
Hint: All elements should be the same type of value so that we can iterate
through the list without running into unexpected values.
>
Obtenir des éléments
> ourList = [1,2,3,4,5]
[1,2,3,4,5] : List number
>
> firstElement = List.head ourList
Just 1 : Maybe Int
>
> allButFirst = List.tail ourList
Just [2,3,4,5] : Maybe (List Int)
Cet encapsulation dans le type Maybe se produit à cause du scénario suivant:
Que devrait retourner List.head pour une liste vide? (Rappelez-vous, Elm n'a pas d'exceptions ni de null.)
> headOfEmpty = List.head []
Nothing : Maybe Int
>
> tailOfEmpty = List.tail []
Nothing : Maybe (List Int)
>
> tailOfAlmostEmpty = List.tail [1] -- warning ... List is a *linked list* :)
Just [] : Maybe (List Int)
Transformer chaque élément d'une liste
List.map : (a -> b) -> List a -> List b est une fonction d'ordre supérieur qui applique une fonction à un paramètre à chaque élément d'une liste, renvoyant une nouvelle liste avec les valeurs modifiées.
import String
ourList : List String
ourList =
["wubba", "lubba", "dub", "dub"]
lengths : List Int
lengths =
List.map String.length ourList
-- [5,5,3,3]
slices : List String
slices =
List.map (String.slice 1 3) ourList
-- ["ub", "ub", "ub", "ub"]
Si vous avez besoin de connaître l’index des éléments, vous pouvez utiliser List.indexedMap : (Int -> a -> b) -> List a -> List b :
newList : List String
newList =
List.indexedMap (\index element -> String.concat [toString index, ": ", element]) ourList
-- ["0: wubba","1: lubba","2: dub","3: dub"]
Filtrer une liste
List.filter : (a -> Bool) -> List a -> List a est une fonction d'ordre supérieur qui prend une fonction à un paramètre de n'importe quelle valeur à un booléen et applique cette fonction à chaque élément d'une liste donnée, ne garder que les éléments pour lesquels la fonction renvoie True . La fonction que prend List.filter comme premier paramètre est souvent appelée prédicat .
import String
catStory : List String
catStory =
["a", "crazy", "cat", "walked", "into", "a", "bar"]
-- Any word with more than 3 characters is so long!
isLongWord : String -> Bool
isLongWord string =
String.length string > 3
longWordsFromCatStory : List String
longWordsFromCatStory =
List.filter isLongWord catStory
Évaluez ceci dans elm-repl :
> longWordsFromCatStory
["crazy", "walked", "into"] : List String
>
> List.filter (String.startsWith "w") longWordsFromCatStory
["walked"] : List String
Correspondance de motif sur une liste
Nous pouvons faire correspondre les listes comme n'importe quel autre type de données, bien qu'elles soient quelque peu uniques, dans la mesure où le constructeur de la construction des listes est la fonction infixe :: . (Voir l'exemple Création d'une liste pour en savoir plus sur le fonctionnement)
matchMyList : List SomeType -> SomeOtherType
matchMyList myList =
case myList of
[] ->
emptyCase
(theHead :: theRest) ->
doSomethingWith theHead theRest
Nous pouvons faire correspondre autant d'éléments que nous voulons dans la liste:
hasAtLeast2Elems : List a -> Bool
hasAtLeast2Elems myList =
case myList of
(e1 :: e2 :: rest) ->
True
_ ->
False
hasAtLeast3Elems : List a -> Bool
hasAtLeast3Elems myList =
case myList of
(e1 :: e2 :: e3 :: rest) ->
True
_ ->
False
Obtenir le nième élément de la liste
List ne supporte pas "random access", ce qui signifie qu'il faut plus de travail pour obtenir, disons, le cinquième élément de la liste que le premier élément, et par conséquent, il n'y a pas de fonction List.get nth list . Il faut aller depuis le début ( 1 -> 2 -> 3 -> 4 -> 5 ).
Si vous avez besoin d'un accès aléatoire, vous obtiendrez de meilleurs résultats (et performances) avec des structures de données à accès aléatoire, comme Array , où prendre le premier élément nécessite autant de travail que, par exemple, le 1000ème. (complexité O (1)).
Néanmoins, il est possible (mais découragé) d’obtenir le nième élément:
get : Int -> List a -> Maybe a
get nth list =
list
|> List.drop (nth - 1)
|> List.head
fifth : Maybe Int
fifth = get 5 [1..10]
-- = Just 5
nonexistent : Maybe Int
nonexistent = get 5 [1..3]
-- = Nothing
Encore une fois, cela prend beaucoup plus de travail, plus le nth argument est grand.
Réduire une liste à une valeur unique
Dans Elm, les fonctions de réduction sont appelées "folds", et il existe deux méthodes standard pour "plier" les valeurs: de gauche à foldl , et de droite à droite, foldr .
> List.foldl (+) 0 [1,2,3]
6 : number
Les arguments de foldl et foldr sont les suivants:
- fonction de réduction :
newValue -> accumulator -> accumulator - valeur de départ de l' accumulateur
- liste pour réduire
Un autre exemple avec une fonction personnalisée:
type alias Counts =
{ odd : Int
, even : Int
}
addCount : Int -> Counts -> Counts
addCount num counts =
let
(incOdd, incEven) =
if num `rem` 2 == 0
then (0,1)
else (1,0)
in
{ counts
| odd = counts.odd + incOdd
, even = counts.even + incEven
}
> List.foldl
addCount
{ odd = 0, even = 0 }
[1,2,3,4,5]
{ odd = 3, even = 2 } : Counts
Dans le premier exemple ci-dessus, le programme se présente comme suit:
List.foldl (+) 0 [1,2,3]
3 + (2 + (1 + 0))
3 + (2 + 1)
3 + 3
6
List.foldr (+) 0 [1,2,3]
1 + (2 + (3 + 0))
1 + (2 + 3)
1 + 5
6
Dans le cas d'une fonction commutative comme (+) il n'y a pas vraiment de différence.
Mais voyez ce qui se passe avec (::) :
List.foldl (::) [] [1,2,3]
3 :: (2 :: (1 :: []))
3 :: (2 :: [1])
3 :: [2,1]
[3,2,1]
List.foldr (::) [] [1,2,3]
1 :: (2 :: (3 :: []))
1 :: (2 :: [3])
1 :: [2,3]
[1,2,3]
Créer une liste en répétant une valeur
> List.repeat 3 "abc"
["abc","abc","abc"] : List String
Vous pouvez donner à List.repeat n'importe quelle valeur:
> List.repeat 2 {a = 1, b = (2,True)}
[{a = 1, b = (2,True)}, {a = 1, b = (2,True)}]
: List {a : Int, b : (Int, Bool)}
Trier une liste
Par défaut, List.sort trie par ordre croissant.
> List.sort [3,1,5]
[1,3,5] : List number
List.sort besoin que les éléments de la liste soient comparable . Cela signifie: String , Char , number ( Int et Float ), List de comparable ou tuple de comparable .
> List.sort [(5,"ddd"),(4,"zzz"),(5,"aaa")]
[(4,"zzz"),(5,"aaa"),(5,"ddd")] : List ( number, String )
> List.sort [[3,4],[2,3],[4,5],[1,2]]
[[1,2],[2,3],[3,4],[4,5]] : List (List number)
Vous ne pouvez pas trier les listes de Bool ou d'objets avec List.sort . Pour cela, voir Trier une liste avec un comparateur personnalisé.
> List.sort [True, False]
-- error, can't compare Bools
Tri d'une liste avec un comparateur personnalisé
List.sortWith vous permet de trier les listes avec des données de n'importe quelle forme - vous leur fournissez une fonction de comparaison.
compareBools : Bool -> Bool -> Order
compareBools a b =
case (a,b) of
(False, True) ->
LT
(True, False) ->
GT
_ ->
EQ
> List.sortWith compareBools [False, True, False, True]
[False, False, True, True] : List Bool
Inverser une liste
Note: ceci n'est pas très efficace en raison de la nature de la List (voir Remarques ci-dessous). Il vaudra mieux construire la liste de la bonne manière depuis le début que de la construire et de l’inverser.
> List.reverse [1,3,5,7,9]
[9,7,5,3,1] : List number
Tri d'une liste par ordre décroissant
Par défaut, List.sort trie par ordre croissant, avec la fonction de compare .
Il existe deux manières de trier par ordre décroissant: une efficace et une inefficace.
- Le moyen efficace :
List.sortWithet une fonction de comparaison décroissante.
descending a b =
case compare a b of
LT -> GT
EQ -> EQ
GT -> LT
> List.sortWith descending [1,5,9,7,3]
[9,7,5,3,1] : List number
- La manière inefficace (déconseillée!) :
List.sortpuisList.reverse.
> List.reverse (List.sort [1,5,9,7,3])
[9,7,5,3,1] : List number
Trier une liste par une valeur dérivée
List.sortBy permet d'utiliser une fonction sur les éléments et d'utiliser son résultat pour la comparaison.
> List.sortBy String.length ["longest","short","medium"]
["short","medium","longest"] : List String
-- because the lengths are: [7,5,6]
Il fonctionne aussi très bien avec les accesseurs de disques:
people =
[ { name = "John", age = 43 }
, { name = "Alice", age = 30 }
, { name = "Rupert", age = 12 }
]
> List.sortBy .age people
[ { name = "Rupert", age = 12 }
, { name = "Alice", age = 30 }
, { name = "John", age = 43 }
] : List {name: String, age: number}
> List.sortBy .name people
[ { name = "Alice", age = 30 }
, { name = "John", age = 43 }
, { name = "Rupert", age = 12 }
] : List {name: String, age: number}