Elm Language
Listor och Iteration
Sök…
Anmärkningar
List ( länkad lista ) lyser i sekvensiell åtkomst :
- åtkomst till det första elementet
- förbereda till framsidan av listan
- ta bort från listans framsida
Å andra sidan är det inte idealiskt för slumpmässig åtkomst (dvs. att få det n: a elementet) och genomföra i omvänd ordning , och du kan få bättre tur (och prestanda) med Array datastrukturen.
Skapa en lista efter intervall
Innan 0.18.0 kan du skapa områden som detta:
> range = [1..5]
[1,2,3,4,5] : List number
>
> negative = [-5..3]
[-5,-4,-3,-2,-1,0,1,2,3] : List number
I 0.18.0 har syntaxen [1..5] tagits bort .
> 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
Områden som skapas av denna syntax är alltid inkluderande och steget är alltid 1 .
Skapa en 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
>
Under huven är List ( länkad lista ) konstruerad av :: -funktionen (kallas "nackdelar"), som tar två argument: ett element, känt som huvudet, och en (eventuellt tom) lista som huvudet är förberedt för.
> withoutSyntaxSugar = 1 :: []
[1] : List number
>
> longerOne = 1 :: 2 :: 3 :: []
[1,2,3] : List number
>
> nonemptyTail = 1 :: [2]
[1,2] : List number
>
List kan bara ta värden av en typ, så något som [1,"abc"] är inte möjligt. Om du behöver detta, använd 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.
>
Få element
> 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)
Denna inpackning i Maybe typen händer på grund av följande scenario:
Vad ska List.head returnera för en tom lista? (Kom ihåg att Elm inte har undantag eller noll.)
> 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)
Omvandla varje element i en lista
List.map : (a -> b) -> List a -> List b är en högre ordningsfunktion som tillämpar en enparameterfunktion på varje element i en lista och returnerar en ny lista med de ändrade värdena.
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"]
Om du behöver känna till indexet för elementen kan du använda 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"]
Filtrera en lista
List.filter : (a -> Bool) -> List a -> List a är en högre ordningsfunktion som tar en enparameterfunktion från vilket värde som helst till en booleska, och tillämpar den funktionen för varje element i en given lista, behåller bara de element för vilka funktionen returnerar True på. Funktionen som List.filter tar som sin första parameter benämns ofta ett predikat .
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
Utvärdera detta i elm-repl :
> longWordsFromCatStory
["crazy", "walked", "into"] : List String
>
> List.filter (String.startsWith "w") longWordsFromCatStory
["walked"] : List String
Mönstermatchning på en lista
Vi kan matcha på listor som alla andra datatyper, även om de är något unika, eftersom konstruktören för att bygga upp listor är infixfunktionen :: . (Se exemplet Skapa en lista för mer information om hur det fungerar.)
matchMyList : List SomeType -> SomeOtherType
matchMyList myList =
case myList of
[] ->
emptyCase
(theHead :: theRest) ->
doSomethingWith theHead theRest
Vi kan matcha så många element i listan som vi vill:
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
Få det nionde elementet från listan
List stöder inte "slumpmässig åtkomst", vilket innebär att det kräver mer arbete för att säga, det femte elementet från listan än det första elementet, och som ett resultat finns det ingen List.get nth list . Man måste gå hela vägen från början ( 1 -> 2 -> 3 -> 4 -> 5 ).
Om du behöver slumpmässig åtkomst kan du få bättre resultat (och prestanda) med datastrukturer med slumpmässig åtkomst, som Array , där du tar det första elementet med samma mängd arbete som att ta, säga, 1000: e. (komplexitet O (1)).
Ändå är det möjligt (men avskräckt) att få det n: a elementet:
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
Återigen tar detta betydligt mer arbete desto större är det nth argumentet.
Minska en lista till ett enda värde
I Elm kallas reduceringsfunktioner "veck", och det finns två standardmetoder för att "vika" värden upp: från vänster, foldl och från höger, foldr .
> List.foldl (+) 0 [1,2,3]
6 : number
Argumenten för att foldl och foldr är:
- reducerande funktion :
newValue -> accumulator -> accumulator - ackumulatorens startvärde
- lista för att minska
Ett ytterligare exempel med anpassad funktion:
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
I det första exemplet ovan går programmet så här:
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
När det gäller en kommutativ funktion som (+) finns det egentligen ingen skillnad.
Men se vad som händer med (::) :
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]
Skapa en lista genom att upprepa ett värde
> List.repeat 3 "abc"
["abc","abc","abc"] : List String
Du kan ge List.repeat valfritt värde:
> List.repeat 2 {a = 1, b = (2,True)}
[{a = 1, b = (2,True)}, {a = 1, b = (2,True)}]
: List {a : Int, b : (Int, Bool)}
Sortera en lista
Som standard sorterar List.sort i stigande ordning.
> List.sort [3,1,5]
[1,3,5] : List number
List.sort behöver att List.sort är comparable . Det betyder: String , Char , number ( Int och Float ), List över comparable eller tupel av 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)
Du kan inte sortera listor över Bool eller objekt med List.sort . Se Sortera en lista med anpassad komparator.
> List.sort [True, False]
-- error, can't compare Bools
Sortera en lista med anpassad komparator
List.sortWith låter dig sortera listor med data av vilken form som helst - du ger den en jämförelsefunktion.
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
Omvända en lista
Obs: detta är inte särskilt effektivt på grund av List karaktär (se anmärkningar nedan). Det kommer att vara bättre att konstruera listan på "rätt" sätt från början än att konstruera den och sedan vända den.
> List.reverse [1,3,5,7,9]
[9,7,5,3,1] : List number
Sortera en lista i fallande ordning
Som standard sorterar List.sort i stigande ordning med compare funktionen.
Det finns två sätt att sortera i fallande ordning: ett effektivt och ett ineffektivt.
- Det effektiva sättet :
List.sortWithoch en fallande jämförelsefunktion.
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
- Det ineffektiva sättet (avskräckt!) :
List.sortoch sedanList.reverse.
> List.reverse (List.sort [1,5,9,7,3])
[9,7,5,3,1] : List number
Sortera en lista efter ett härledt värde
List.sortBy tillåter att använda en funktion på elementen och använda dess resultat för jämförelsen.
> List.sortBy String.length ["longest","short","medium"]
["short","medium","longest"] : List String
-- because the lengths are: [7,5,6]
Det fungerar också fint med skivtillbehör:
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}