Elm Language
Elenchi e Iterazioni
Ricerca…
Osservazioni
L' List ( elenco collegato ) brilla in accesso sequenziale :
- accedere al primo elemento
- anteponendo in cima alla lista
- cancellando dalla parte anteriore della lista
D'altra parte, non è l'ideale per l'accesso casuale (ad esempio ottenere l'ennesimo elemento) e la traversione in ordine inverso , e si potrebbe avere migliore fortuna (e prestazioni) con la struttura dati Array .
Creazione di un elenco per intervallo
Prima di 0.18.0 puoi creare intervalli come questo:
> range = [1..5]
[1,2,3,4,5] : List number
>
> negative = [-5..3]
[-5,-4,-3,-2,-1,0,1,2,3] : List number
In 0.18.0 La sintassi [1..5] è stata rimossa .
> 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
Gli intervalli creati da questa sintassi sono sempre inclusivi e il passo è sempre 1 .
Creare una lista
> 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
>
Sotto la cappa, List ( lista collegata ) è costruita dalla funzione :: (chiamata "contro"), che prende due argomenti: un elemento, noto come la testa, e un elenco (eventualmente vuoto) a cui è preposta la testa.
> withoutSyntaxSugar = 1 :: []
[1] : List number
>
> longerOne = 1 :: 2 :: 3 :: []
[1,2,3] : List number
>
> nonemptyTail = 1 :: [2]
[1,2] : List number
>
List può assumere solo valori di un tipo, quindi qualcosa come [1,"abc"] non è possibile. Se ti serve, usa le tuple.
> 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.
>
Ottenere elementi
> 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)
Questo inserimento nel tipo Maybe verifica a causa del seguente scenario:
Cosa dovrebbe restituire List.head per una lista vuota? (Ricorda, Elm non ha eccezioni o 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)
Trasformare ogni elemento di una lista
List.map : (a -> b) -> List a -> List b è una funzione di ordine superiore che applica una funzione a parametro unico a ciascun elemento di una lista, restituendo una nuova lista con i valori modificati.
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"]
Se è necessario conoscere l'indice degli elementi è possibile utilizzare 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"]
Filtrare un elenco
List.filter : (a -> Bool) -> List a -> List a è una funzione di ordine superiore che accetta una funzione a parametro unico da qualsiasi valore a un valore booleano e applica tale funzione a ogni elemento di una determinata lista, mantenendo solo quegli elementi per i quali la funzione restituisce True on. La funzione che List.filter prende come primo parametro viene spesso definita un predicato .
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
Valuta questo in elm-repl :
> longWordsFromCatStory
["crazy", "walked", "into"] : List String
>
> List.filter (String.startsWith "w") longWordsFromCatStory
["walked"] : List String
Pattern Matching su un elenco
Possiamo abbinare gli elenchi come qualsiasi altro tipo di dati, sebbene siano un po 'unici, in quanto il costruttore per la creazione di elenchi è la funzione infisso :: . (Vedere l'esempio Creazione di un elenco per ulteriori informazioni su come funziona.)
matchMyList : List SomeType -> SomeOtherType
matchMyList myList =
case myList of
[] ->
emptyCase
(theHead :: theRest) ->
doSomethingWith theHead theRest
Possiamo abbinare tanti elementi nella lista che vogliamo:
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
Ottenere l'ennesimo elemento dalla lista
List non supporta "l'accesso casuale", il che significa che ci vuole più lavoro per ottenere, diciamo, il quinto elemento dalla lista rispetto al primo elemento, e di conseguenza non c'è alcuna funzione List.get nth list . Uno deve andare dall'inizio ( 1 -> 2 -> 3 -> 4 -> 5 ).
Se hai bisogno dell'accesso casuale, potresti ottenere risultati migliori (e prestazioni) con strutture di dati ad accesso casuale, come Array , dove prendere il primo elemento richiede la stessa quantità di lavoro di prendere, per esempio, il millesimo. (complessità O (1)).
Tuttavia, è possibile (ma scoraggiato) ottenere l'ennesimo elemento:
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
Di nuovo, questo richiede molto più lavoro, più grande è l' nth argomento.
Ridurre un elenco a un singolo valore
A Elm, funzioni riducenti sono chiamati "pieghe", e ci sono due metodi standard di "piega" valori fino: sulla sinistra, foldl , e da destra, foldr .
> List.foldl (+) 0 [1,2,3]
6 : number
Gli argomenti a foldl e foldr sono:
- funzione di riduzione :
newValue -> accumulator -> accumulator - accumulatore valore iniziale
- elenco da ridurre
Un altro esempio con funzione personalizzata:
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
Nel primo esempio sopra il programma va in questo modo:
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
Nel caso di una funzione commutativa come (+) non c'è davvero una differenza.
Ma vedi cosa succede con (::) :
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]
Creare una lista ripetendo un valore
> List.repeat 3 "abc"
["abc","abc","abc"] : List String
Puoi dare a List.repeat qualsiasi valore:
> List.repeat 2 {a = 1, b = (2,True)}
[{a = 1, b = (2,True)}, {a = 1, b = (2,True)}]
: List {a : Int, b : (Int, Bool)}
Ordinamento di una lista
Per impostazione predefinita, List.sort ordina in ordine crescente.
> List.sort [3,1,5]
[1,3,5] : List number
List.sort richiede che gli elementi della lista siano comparable . Ciò significa: String , Char , number ( Int e Float ), List di comparable o tupla 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)
Non è possibile ordinare elenchi di Bool o oggetti con List.sort . Per questo vedi Ordinamento di un elenco con comparatore personalizzato.
> List.sort [True, False]
-- error, can't compare Bools
Ordinamento di un elenco con comparatore personalizzato
List.sortWith consente di ordinare elenchi con dati di qualsiasi forma: lo si fornisce con una funzione di confronto.
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
Inversione di una lista
Nota: questo non è molto efficiente a causa della natura di List (vedere Note sotto). Sarà meglio costruire la lista la via "giusta" dall'inizio piuttosto che costruirla e poi invertirla.
> List.reverse [1,3,5,7,9]
[9,7,5,3,1] : List number
Ordinamento di un elenco in ordine decrescente
Di default, List.sort ordina in ordine crescente, con la funzione di compare .
Esistono due modi per ordinare in ordine decrescente: uno efficiente e uno inefficiente.
- Il modo efficace :
List.sortWithe una funzione di confronto decrescente.
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
- Il modo inefficiente (scoraggiato!) :
List.sorte quindiList.reverse.
> List.reverse (List.sort [1,5,9,7,3])
[9,7,5,3,1] : List number
Ordinamento di un elenco in base a un valore derivato
List.sortBy consente di utilizzare una funzione sugli elementi e utilizzare il suo risultato per il confronto.
> List.sortBy String.length ["longest","short","medium"]
["short","medium","longest"] : List String
-- because the lengths are: [7,5,6]
Funziona egregiamente con i programmi di accesso ai record:
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}