elm-community / list-extra / List.Extra

Convenience functions for working with List

Basics

last : List a -> Maybe a

Extract the last element of a list.

last [ 1, 2, 3 ]
--> Just 3

last []
--> Nothing

init : List a -> Maybe (List a)

Return all elements of the list except the last one.

init [ 1, 2, 3 ]
--> Just [ 1, 2 ]

init []
--> Nothing

getAt : Basics.Int -> List a -> Maybe a

Returns Just the element at the given index in the list, or Nothing if the index is out of range.

uncons : List a -> Maybe ( a, List a )

Decompose a list into its head and tail. If the list is empty, return Nothing. Otherwise, return Just (x, xs), where x is head and xs is tail.

uncons [1,2,3]
--> Just (1, [2,3])

uncons []
--> Nothing

unconsLast : List a -> Maybe ( a, List a )

Decompose a list into its body and last element. If the list is empty, return Nothing. Otherwise, return Just (x, xs), where x is the last element and xs is the body.

unconsLast [1,2,3]
--> Just (3, [1,2])

unconsLast []
--> Nothing

maximumBy : (a -> comparable) -> List a -> Maybe a

Find the first maximum element in a list using a comparable transformation

maximumWith : (a -> a -> Basics.Order) -> List a -> Maybe a

Find the first maximum element in a list using a comparison function

maximumWith compare []
--> Nothing

maximumWith
  (\x y -> compare x.val y.val)
  [{id=1, val=1}, {id=2, val=2}, {id=3,val=2}]
--> Just { id = 2, val = 2 }

minimumBy : (a -> comparable) -> List a -> Maybe a

Find the first minimum element in a list using a comparable transformation

minimumWith : (a -> a -> Basics.Order) -> List a -> Maybe a

Find the first minimum element in a list using a comparison function

minimumWith compare []
--> Nothing
minimumWith
  (\x y -> compare x.val y.val)
  [{id=1, val=2}, {id=2, val=1}, {id=3,val=1}]
--> Just { id = 2, val = 1 }

andMap : List a -> List (a -> b) -> List b

Map functions taking multiple arguments over multiple lists. Each list should be of the same length.

toIntFunctions : List (Float -> Int)
toIntFunctions =
    [ round
    , floor
    , ceiling
    , truncate
    ]

toIntFunctions
    |> andMap [ -1.5, -1.5, -1.5, -1.5 ]
    --> [ -1, -2, -1, -1 ]


math : List (Int -> Int)
math =
    [ (+) 1
    , (*) 2
    , (*) 3 >> (+) 1
    ]

math
    |> andMap [ 1, 2, 3 ]
    --> [ 2, 4, 10 ]

andThen : (a -> List b) -> List a -> List b

Equivalent to concatMap. For example, suppose you want to have a cartesian product of [1,2] and [3,4]:

[ 1, 2 ]
    |> andThen
        (\x ->
            [ 3, 4 ]
                |> andThen (\y -> [ ( x, y ) ])
        )
    --> [ ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ) ]

Now suppose we want to have a cartesian product between the first list and the second list and its doubles:

[ 1, 2 ]
    |> andThen
        (\x ->
            [ 3, 4 ]
                |> andThen
                    (\y ->
                        [ y, y * 2 ]
                            |> andThen (\z -> [ ( x, z ) ])
                    )
        )
    --> [ ( 1, 3 ), ( 1, 6 ), ( 1, 4 ), ( 1, 8 ), ( 2, 3 ), ( 2, 6 ), ( 2, 4 ), ( 2, 8 )]

Advanced functional programmers will recognize this as the implementation of bind operator (>>=) for lists from the Monad typeclass.

reverseMap : (a -> b) -> List a -> List b

reverseMap f xs gives the same result as List.reverse (List.map f xs), but is tail-recursive and slightly more efficient.

reverseMap sqrt [ 1, 4, 9 ]
--> [ 3, 2, 1 ]

takeWhile : (a -> Basics.Bool) -> List a -> List a

Take elements in order as long as the predicate evaluates to True

dropWhile : (a -> Basics.Bool) -> List a -> List a

Drop elements in order as long as the predicate evaluates to True

unique : List a -> List a

Remove duplicate values, keeping the first instance of each element which appears more than once.

unique [ 0, 1, 1, 0, 1 ]
--> [ 0, 1 ]

uniqueBy : (a -> b) -> List a -> List a

Drop duplicates where what is considered to be a duplicate is the result of first applying the supplied function to the elements of the list.

allDifferent : List a -> Basics.Bool

Indicate if list has duplicate values.

allDifferent [ 0, 1, 1, 0, 1 ]
--> False

allDifferent [ 0, 1, 2]
--> True

allDifferentBy : (a -> b) -> List a -> Basics.Bool

Indicate if list has duplicate values when supplied function are applied on each values.

setIf : (a -> Basics.Bool) -> a -> List a -> List a

Replace all values that satisfy a predicate with a replacement value.

setAt : Basics.Int -> a -> List a -> List a

Set a value in a list by index. Return the original list if the index is out of range.

setAt 0 42 [ 1, 2, 3 ]
--> [ 42, 2, 3 ]

remove : a -> List a -> List a

Remove the first occurrence of a value from a list.

updateIf : (a -> Basics.Bool) -> (a -> a) -> List a -> List a

Replace all values that satisfy a predicate by calling an update function.

updateAt : Basics.Int -> (a -> a) -> List a -> List a

Replace a value at a specific index by calling an update function. Return the original list if the index is out of range.

updateAt 0 ((+) 1) [ 1, 2, 3 ]
--> [ 2, 2, 3 ]

See also updateIfIndex.

updateIfIndex : (Basics.Int -> Basics.Bool) -> (a -> a) -> List a -> List a

Replace a value at an index that satisfies a predicate, by calling an update function.

updateIfIndex ((==) 2) ((+) 1) [ 1, 2, 3 ]
--> [ 1, 2, 4 ]

See also updateAt.

removeAt : Basics.Int -> List a -> List a

Remove the element at an index from a list. Return the original list if the index is out of range.

removeAt 0 [ 1, 2, 3 ]
--> [ 2, 3 ]

See also removeIfIndex.

removeIfIndex : (Basics.Int -> Basics.Bool) -> List a -> List a

Remove an element at an index that satisfies a predicate.

removeIfIndex ((==) 2) [ 1, 2, 3 ]
--> [ 1, 2 ]

See also removeAt.

filterNot : (a -> Basics.Bool) -> List a -> List a

Take a predicate and a list, and return a list that contains elements which fails to satisfy the predicate. This is equivalent to List.filter (not << predicate) list.

isEven : Int -> Bool
isEven i =
    modBy 2 i == 0

filterNot isEven [ 1, 2, 3, 4 ]
--> [ 1, 3 ]

swapAt : Basics.Int -> Basics.Int -> List a -> List a

Swap two values in a list by index. Return the original list if the index is out of range. If the same index is supplied twice the operation has no effect.

swapAt 1 2 [ 1, 2, 3 ]
--> [ 1, 3, 2 ]

stableSortWith : (a -> a -> Basics.Order) -> List a -> List a

Similar to List.sortWith, this sorts values with a custom comparison function. Unlike List.sortWith, this sort is guaranteed to be a stable sort. Note that List.sortWith is faster and is preferred if sort stability is not required.

List transformations

intercalate : List a -> List (List a) -> List a

Take a list and a list of lists, insert that list between every list in the list of lists, concatenate the result. intercalate xs xss is equivalent to concat (intersperse xs xss).

intercalate [ 0, 0 ] [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]
--> [ 1, 2, 0, 0, 3, 4, 0, 0, 5, 6 ]

transpose : List (List a) -> List (List a)

Transpose rows and columns of the list of lists.

transpose [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
--> [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ]

transpose [ [ 10, 11 ], [ 20, 40 ], [ 30, 31, 32, 400 ] ]
--> [ [ 10, 20, 30 ], [ 11, 40, 31 ] ]

subsequences : List a -> List (List a)

Return the list of all subsequences of a list.

subsequences [ 1, 2, 3 ]
--> [ [], [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ]

permutations : List a -> List (List a)

Return the list of of all permutations of a list. The result is in lexicographic order.

permutations [ 1, 2, 3 ]
--> [ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ]

interweave : List a -> List a -> List a

Return a list that contains elements from the two provided, in alternate order. If one list runs out of items, append the items from the remaining list.

interweave [ 1, 3 ] [ 2, 4 ]
--> [ 1, 2, 3, 4 ]

interweave [ 1, 3, 5, 7 ] [ 2, 4 ]
--> [ 1, 2, 3, 4, 5, 7 ]

interweave [ 4, 9, 16 ] [ 2, 3, 5, 7 ]
--> [ 4, 2, 9, 3, 16, 5, 7 ]

cartesianProduct : List (List a) -> List (List a)

Return the cartesian product of a list of lists. If one list is empty, the result is an empty list. If the list of lists is empty, the result is an empty singleton.

cartesianProduct [ [ 1, 2 ], [ 3, 4, 5 ], [ 6 ] ]
--> [ [ 1, 3, 6 ], [ 1, 4, 6 ], [ 1, 5, 6 ], [ 2, 3, 6 ], [ 2, 4, 6 ], [ 2, 5, 6 ] ]

cartesianProduct [ [ 1, 2 ] ]
--> [ [ 1 ], [ 2 ] ]

cartesianProduct [ [ 1, 2 ], [], [ 6 ] ]
--> []

cartesianProduct [ [] ]
--> []

cartesianProduct []
--> [ [] ]

uniquePairs : List a -> List ( a, a )

Return all ways to pair the elements of the list. (Essentially, enumerate the possible "handshakes.")

The order of the pair elements doesn't matter, so if (1,2) is a returned pair, we don't return (2,1).

In more mathematical terms these are 2-combinations without repetition.

uniquePairs [ 1, 2, 3, 4 ]
--> [ ( 1, 2 ), ( 1, 3 ), ( 1, 4 ), ( 2, 3 ), ( 2, 4 ), ( 3, 4 ) ]

In this example, everybody shakes hands with three other people.

Folds

foldl1 : (a -> a -> a) -> List a -> Maybe a

Variant of foldl that has no starting value argument and treats the head of the list as its starting value. If the list is empty, return Nothing.

foldl1 (-) [ 1, 2, 3, 4 ]
--> Just 2

foldl1 (++) [ "a", "b", "c" ]
--> Just "cba"

foldl1 min []
--> Nothing

Note: This function changed in a major way between version 7.0.0 and 8.0.0 of this package. The function foldl1 took in 7.0.0 was b -> a -> b consistent with the Haskell implementation of foldl, but now its a -> b -> b, consistent with List.foldl. This function behaves differently in a breaking way, even though its type signature is the same.

foldr1 : (a -> a -> a) -> List a -> Maybe a

Variant of foldr that has no starting value argument and treats the last element of the list as its starting value. If the list is empty, return Nothing.

foldr1 (-) [ 1, 2, 3, 4 ]
--> Just -2

foldr1 (++) [ "a", "b", "c" ]
--> Just "abc"

foldr1 min []
--> Nothing

indexedFoldl : (Basics.Int -> a -> b -> b) -> b -> List a -> b

Variant of foldl that passes the index of the current element to the step function. indexedFoldl is to List.foldl as List.indexedMap is to List.map.

indexedFoldr : (Basics.Int -> a -> b -> b) -> b -> List a -> b

Variant of foldr that passes the index of the current element to the step function. indexedFoldr is to List.foldr as List.indexedMap is to List.map.


type Step a
    = Continue a
    | Stop a

A custom type used for stoppable folds.

stoppableFoldl : (a -> b -> Step b) -> b -> List a -> b

A foldl that can stop early instead of traversing the whole list.

stoppableFoldl
    (\n acc ->
        if acc >= 50 then
            Stop acc
        else
            Continue (n + acc)
    )
    0
    (List.range 1 10000)
--> 55

Building lists

scanl : (a -> b -> b) -> b -> List a -> List b

Reduce a list from the left, building up all of the intermediate results into a list.

scanl (+) 0 [ 1, 2, 3, 4 ]
--> [ 0, 1, 3, 6, 10 ]

scanl1 : (a -> a -> a) -> List a -> List a

scanl1 is a variant of scanl that has no starting value argument.

Compare:

scanl (+) 0 [ 1, 2, 3 ]
--> [ 0, 1, 3, 6 ]

scanl1 (+) [ 1, 2, 3 ]
--> [ 1, 3, 6 ]

scanl (-) 0 [ 1, 2, 3 ]
--> [ 0, 1, 1, 2 ]

scanl1 (-) [ 1, 2, 3 ]
--> [ 1, 1, 2 ]

scanr : (a -> b -> b) -> b -> List a -> List b

scanr is a right-to-left dual of scanl. Note that:

head (scanr f z xs) == foldr f z xs

Examples:

scanr (+) 0 [ 1, 2, 3 ]
--> [ 6, 5, 3, 0 ]

scanr (-) 0 [ 1, 2, 3 ]
--> [ 2, -1, 3, 0 ]

scanr1 : (a -> a -> a) -> List a -> List a

scanr1 is a variant of scanr that has no starting value argument.

scanr1 (+) [ 1, 2, 3 ]
--> [ 6, 5, 3 ]

scanr1 (-) [ 1, 2, 3 ]
--> [ 2, -1, 3 ]

mapAccuml : (a -> b -> ( a, c )) -> a -> List b -> ( a, List c )

The mapAccuml function behaves like a combination of map and foldl; it applies a function to each element of a list, passing an accumulating parameter from left to right, and returning a final value of this accumulator together with the new list.

mapAccuml f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] )

--        x1    x2    x3
--        |     |     |
--  a0 -- f --- f --- f -> a3
--        |     |     |
--        y1    y2    y3

Add a running total to a list of numbers:

mapAccuml (\a x -> ( a + x, ( x, a + x ) )) 0 [ 2, 4, 8 ]
    --> ( 14, [ ( 2, 2 ), ( 4, 6 ), ( 8, 14 ) ] )

Map number by multiplying with accumulated sum:

mapAccuml (\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]
    --> ( 19, [ 10, 28, 88 ] )

mapAccumr : (a -> b -> ( a, c )) -> a -> List b -> ( a, List c )

The mapAccumr function behaves like a combination of map and foldr; it applies a function to each element of a list, passing an accumulating parameter from right to left, and returning a final value of this accumulator together with the new list.

mapAccumr f a0 [ x1, x2, x3 ] == ( a3, [ y1, y2, y3 ] )

--        x1    x2    x3
--        |     |     |
--  a3 <- f --- f --- f -- a0
--        |     |     |
--        y1    y2    y3

Add a count of remaining elements:

mapAccumr (\a x -> ( a + 1, ( x, a ) )) 0 [ 2, 4, 8 ]
    --> ( 3, [ ( 2, 2 ), ( 4, 1 ), ( 8, 0 ) ] )

Map number by multiplying with right-to-left accumulated sum:

mapAccumr (\a x -> ( a + x, a * x )) 5 [ 2, 4, 8 ]
    --> ( 19, [ 34, 52, 40 ] )

unfoldr : (b -> Maybe ( a, b )) -> b -> List a

The unfoldr function is "dual" to foldr. foldr reduces a list to a summary value, unfoldr builds a list from a seed. The function takes a function and a starting element. It applies the function to the element. If the result is Just (a, b), a is accumulated and the function is applied to b. If the result is Nothing, the list accumulated so far is returned.

subtractOneUntilZero : Int -> Maybe (Int, Int)
subtractOneUntilZero i =
    if i /= 0 then
        Just (i, i - 1)
    else
        Nothing

unfoldr subtractOneUntilZero 5
--> [ 5, 4, 3, 2, 1 ]

iterate : (a -> Maybe a) -> a -> List a

Returns a list of repeated applications of f. If f returns Nothing the iteration will stop. If it returns Just y then y will be added to the list and the iteration will continue with f y.

collatz : Int -> Maybe Int
collatz n =
    if n == 1 then
        Nothing
    else
        Just <|
            if modBy 2 n == 0 then
                n // 2
            else
                3 * n + 1

iterate collatz 13
--> [13,40,20,10,5,16,8,4,2,1]

initialize : Basics.Int -> (Basics.Int -> a) -> List a

Initialize a list of some length with some function.

initialize n f creates a list of length n with the element at index i initialized to the result of f i.

cycle : Basics.Int -> List a -> List a

Creates a list of the given length whose elements are obtained by cycling through the elements of the given list. If the given list is empty, the resulting list will be empty.

cycle 6 [ 4, 7, 8 ]
--> [ 4, 7, 8, 4, 7, 8 ]

cycle 4 [ 'a', 'b', 'c' ]
--> [ 'a', 'b', 'c', 'a' ]

cycle 9001 []
--> []

cycle 2 [ 1, 2, 3, 4, 5 ]
--> [ 1, 2 ]

reverseRange : Basics.Int -> Basics.Int -> List Basics.Int

Create a list of numbers, every element decreasing by one. You give the highest and lowest number that should be in the list. More efficient than calling List.reverse (List.range lo hi)

range 6 3 == [ 6, 5, 4, 3 ]

range 3 3 == [ 3 ]

range 3 6 == []

Sublists

splitAt : Basics.Int -> List a -> ( List a, List a )

Take a number and a list, return a tuple of lists, where first part is prefix of the list of length equal the number, and second part is the remainder of the list. splitAt n xs is equivalent to (take n xs, drop n xs).

splitAt 3 [ 1, 2, 3, 4, 5 ]
--> ( [ 1, 2, 3 ], [ 4, 5 ] )

splitAt 1 [ 1, 2, 3 ]
--> ( [ 1 ], [ 2, 3 ] )

splitAt 3 [ 1, 2, 3 ]
--> ( [ 1, 2, 3 ], [] )

splitAt 4 [ 1, 2, 3 ]
--> ( [ 1, 2, 3 ], [] )

splitAt 0 [ 1, 2, 3 ]
--> ( [], [ 1, 2, 3 ] )

splitAt -1 [ 1, 2, 3 ]
--> ( [], [ 1, 2, 3 ] )

splitWhen : (a -> Basics.Bool) -> List a -> Maybe ( List a, List a )

Attempts to split the list at the first element where the given predicate is true. If the predicate is not true for any elements in the list, return nothing. Otherwise, return the split list.

splitWhen (\n -> n == 3) [ 1, 2, 3, 4, 5 ]
--> Just ( [ 1, 2 ], [ 3, 4, 5 ] )

splitWhen (\n -> n == 6) [ 1, 2, 3, 4, 5 ]
--> Nothing

takeWhileRight : (a -> Basics.Bool) -> List a -> List a

Take elements from the right, while predicate still holds.

takeWhileRight ((<) 5) (List.range 1 10)
--> [ 6, 7, 8, 9, 10 ]

dropWhileRight : (a -> Basics.Bool) -> List a -> List a

Drop elements from the right, while predicate still holds.

dropWhileRight ((<) 5) (List.range 1 10)
--> [ 1, 2, 3, 4, 5 ]

span : (a -> Basics.Bool) -> List a -> ( List a, List a )

Take a predicate and a list, return a tuple. The first part of the tuple is the longest prefix of that list, for each element of which the predicate holds. The second part of the tuple is the remainder of the list. span p xs is equivalent to (takeWhile p xs, dropWhile p xs).

span ((>) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]
--> ( [ 1, 2 ], [ 3, 4, 1, 2, 3, 4 ] )

span ((>) 5) [ 1, 2, 3 ]
--> ( [ 1, 2, 3 ], [] )

span ((>) 0) [ 1, 2, 3 ]
--> ( [], [ 1, 2, 3 ] )

break : (a -> Basics.Bool) -> List a -> ( List a, List a )

Take a predicate and a list, return a tuple. The first part of the tuple is the longest prefix of that list, for each element of which the predicate does not hold. The second part of the tuple is the remainder of the list. break p xs is equivalent to (takeWhile (not p) xs, dropWhile (not p) xs).

break ((<) 3) [ 1, 2, 3, 4, 1, 2, 3, 4 ]
--> ( [ 1, 2, 3 ], [ 4, 1, 2, 3, 4 ] )

break ((>) 5) [ 1, 2, 3 ]
--> ( [], [ 1, 2, 3 ] )

break ((<) 5) [ 1, 2, 3 ]
--> ( [ 1, 2, 3 ], [] )

stripPrefix : List a -> List a -> Maybe (List a)

Drop the given prefix from the list. If the list doesn't start with that prefix, return Nothing.

stripPrefix [ 1, 2 ] [ 1, 2, 3, 4 ]
--> Just [ 3, 4 ]

stripPrefix [ 1, 2, 3 ] [ 1, 2, 3, 4, 5 ]
--> Just [ 4, 5 ]

stripPrefix [ 1, 2, 3 ] [ 1, 2, 3 ]
--> Just []

stripPrefix [ 1, 2, 3 ] [ 1, 2 ]
--> Nothing

stripPrefix [ 3, 2, 1 ] [ 1, 2, 3, 4, 5 ]
--> Nothing

group : List a -> List ( a, List a )

Group similar elements together. group is equivalent to groupWhile (==).

group [ 1, 2, 2, 3, 3, 3, 2, 2, 1 ]
--> [ (1, []), (2, [ 2 ]), (3, [ 3, 3 ]), (2, [ 2 ]), ( 1,  []) ]

groupWhile : (a -> a -> Basics.Bool) -> List a -> List ( a, List a )

Group elements together, using a custom comparison test (a -> a -> Bool). Start a new group each time the comparison test doesn't hold for two adjacent elements.

groupWhile uses a non-empty list type (a, List a) since groups necessarily must have at least one member since they are determined by comparing two members.

groupWhile
    (==)
    [ 1, 2, 3 ]
--> [ ( 1, [] ), ( 2, [] ), ( 3, [] ) ]

groupWhile
    (<)
    [ 1, 2, 3, 2, 4, 1, 3, 2, 1 ]
--> [ ( 1, [ 2, 3 ] ), ( 2, [ 4 ] ), ( 1, [ 3 ] ), ( 2, [] ), ( 1, [] ) ]

groupWhile
    (\a b -> a.id == b.id)
    [ { value = 4, id = 9 }, { value = 7, id = 2 }, { value = 1, id = 2 } ]
--> [ ( { value = 4, id = 9 }, [] ), ( { value = 7, id = 2 }, [ { value = 1, id = 2 } ] ) ]

Note: The behavior of this function has changed between major versions 7 and 8. In version 7 there was groupWhile and groupWhileTransitively. The behavior of the two was almost identical, however the transitive function was closer to what users found intuitive about grouping. groupWhileTransitively has been deleted, and groupWhile has been replaced with the version 7s groupWhileTransitively behavior. Furthermore the group type was changed from List a to the non-empty list type (a, List a). Sorry for any inconvenience this may cause.

inits : List a -> List (List a)

Return all initial segments of a list, from shortest to longest, empty list first, the list itself last.

inits [ 1, 2, 3 ]
--> [ [], [ 1 ], [ 1, 2 ], [ 1, 2, 3 ] ]

tails : List a -> List (List a)

Return all final segments of a list, from longest to shortest, the list itself first, empty list last.

tails [ 1, 2, 3 ]
--> [ [ 1, 2, 3 ], [ 2, 3 ], [ 3 ], [] ]

select : List a -> List ( a, List a )

Return all combinations in the form of (element, rest of the list). Read Haskell Libraries proposal for further ideas on how to use this function.

select [ 1, 2, 3, 4 ]
--> [ ( 1, [ 2, 3, 4 ] ), ( 2, [ 1, 3, 4 ] ), ( 3, [ 1, 2, 4 ] ), ( 4, [ 1, 2, 3 ] ) ]

selectSplit : List a -> List ( List a, a, List a )

Return all combinations in the form of (elements before, element, elements after).

selectSplit [ 1, 2, 3 ]
--> [ ( [], 1, [ 2, 3 ] ), ( [ 1 ], 2, [ 3 ] ), ( [ 1, 2 ], 3, [] ) ]

gatherEquals : List a -> List ( a, List a )

Group equal elements together. This is different from group as each sublist will contain all equal elements of the original list. Elements will be grouped in the same order as they appear in the original list. The same applies to elements within each group.

gatherEquals [1,2,1,3,2]
--> [(1,[1]),(2,[2]),(3,[])]

gatherEqualsBy : (a -> b) -> List a -> List ( a, List a )

Group equal elements together. A function is applied to each element of the list and then the equality check is performed against the results of that function evaluation. Elements will be grouped in the same order as they appear in the original list. The same applies to elements within each group.

gatherEqualsBy .age [{age=25},{age=23},{age=25}]
--> [({age=25},[{age=25}]),({age=23},[])]

gatherWith : (a -> a -> Basics.Bool) -> List a -> List ( a, List a )

Group equal elements together using a custom equality function. Elements will be grouped in the same order as they appear in the original list. The same applies to elements within each group.

gatherWith (==) [1,2,1,3,2]
--> [(1,[1]),(2,[2]),(3,[])]

subsequencesNonEmpty : List a -> List ( a, List a )

Return the list of all subsequences of the argument, except for the empty list.

subsequencesNonEmpty [ 1, 2, 3 ]
    == [ [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ]

frequencies : List comparable -> List ( comparable, Basics.Int )

Calculate the number of occurences for each element in a list. Elements will be ordered ascendingly, then grouped in a tuple with the number of occurences.

frequencies [2,1,3,2,3,3]
--> [(1,1),(2,2),(3,3)]

Predicates

isPrefixOf : List a -> List a -> Basics.Bool

Take two lists and return True, if the first list is the prefix of the second list.

isSuffixOf : List a -> List a -> Basics.Bool

Take two lists and return True, if the first list is the suffix of the second list.

isInfixOf : List a -> List a -> Basics.Bool

Return True if all the elements of the first list occur in-order and consecutively anywhere within the second.

isInfixOf [ 5, 7, 11 ] [ 2, 3, 5, 7, 11, 13 ]
--> True

isInfixOf [ 5, 7, 13 ] [ 2, 3, 5, 7, 11, 13 ]
--> False

isInfixOf [ 3, 5, 2 ] [ 2, 3, 5, 7, 11, 13 ]
--> False

isSubsequenceOf : List a -> List a -> Basics.Bool

Return True if all the elements of the first list occur, in order, in the second. The elements do not have to occur consecutively.

isSubsequenceOf
    [ "E", "l", "m" ]
    [ "E", "a", "t", " ", "l", "i", "m", "e", "s" ]
--> True

isSubsequenceOf
    [ "E", "l", "m" ]
    [ "E", "m", "a", "i", "l" ]
--> False

isPermutationOf : List a -> List a -> Basics.Bool

Take two lists and return True, if the first list is a permutation of the second list. In other words: Do the 2 Lists contain the same elements but in a different order?

[ 3, 1, 2 ]
    |> isPermutationOf
        [ 1, 2, 3 ]
--> True

[ 3, 1, 0 ]
    |> isPermutationOf
        [ 1, 2, 3 ]
--> False

[ 3, 1, 2, 2 ]
    |> isPermutationOf
        [ 1, 2, 3 ]
--> False

Searching

notMember : a -> List a -> Basics.Bool

Negation of member.

notMember 1 [ 1, 2, 3 ]
--> False

notMember 4 [ 1, 2, 3 ]
--> True

find : (a -> Basics.Bool) -> List a -> Maybe a

Find the first element that satisfies a predicate and return Just that element. If none match, return Nothing.

find (\num -> num > 5) [ 2, 4, 6, 8 ]
--> Just 6

elemIndex : a -> List a -> Maybe Basics.Int

Return the index of the first occurrence of the element. Otherwise, return Nothing. Indexing starts from 0.

elemIndex 1 [ 1, 2, 3 ]
--> Just 0

elemIndex 4 [ 1, 2, 3 ]
--> Nothing

elemIndex 1 [ 1, 2, 1 ]
--> Just 0

elemIndices : a -> List a -> List Basics.Int

Return all indices of occurrences of the element. If element is not found, return empty list. Indexing starts from 0.

elemIndices 1 [ 1, 2, 3 ]
--> [ 0 ]

elemIndices 4 [ 1, 2, 3 ]
--> []

elemIndices 1 [ 1, 2, 1 ]
--> [ 0, 2 ]

findIndex : (a -> Basics.Bool) -> List a -> Maybe Basics.Int

Take a predicate and a list, return the index of the first element that satisfies the predicate. Otherwise, return Nothing. Indexing starts from 0.

isEven : Int -> Bool
isEven i =
    modBy 2 i == 0

findIndex isEven [ 1, 2, 3 ]
--> Just 1

findIndex isEven [ 1, 3, 5 ]
--> Nothing

findIndex isEven [ 1, 2, 4 ]
--> Just 1

findIndices : (a -> Basics.Bool) -> List a -> List Basics.Int

Take a predicate and a list, return indices of all elements satisfying the predicate. Otherwise, return empty list. Indexing starts from 0.

isEven : Int -> Bool
isEven i =
    modBy 2 i == 0

findIndices isEven [ 1, 2, 3 ]
--> [ 1 ]

findIndices isEven [ 1, 3, 5 ]
--> []

findIndices isEven [ 1, 2, 4 ]
--> [ 1, 2 ]

findMap : (a -> Maybe b) -> List a -> Maybe b

Apply a function that may succeed to values in the list and return the result of the first successful match. If none match, then return Nothing.

mapOverFive : Int -> Maybe Int
mapOverFive num =
    if num > 5 then
        Just (num * 2)
    else
        Nothing

findMap mapOverFive [2, 4, 6, 8]
--> Just 12

This is particularly useful in cases where you have a complex type in a list, and you need to pick out the the first one

type alias HouseModel =
    {}

type Property
    = Rental
    | House HouseModel
    | Commercial

toHouse : Property -> Maybe HouseModel
toHouse property =
    case property of
        House house ->
            Just house

        _ ->
            Nothing

viewFirstHomeOfInterest : Viewer -> List Property -> Html msg
viewFirstHomeOfInterest viewer propertiesQuery =
    propertiesQuery
        |> findMap toHouse
        |> Maybe.map homeView
        |> Maybe.withDefault noHomeView

count : (a -> Basics.Bool) -> List a -> Basics.Int

Returns the number of elements in a list that satisfy a given predicate. Equivalent to List.length (List.filter pred list) but more efficient.

count
    (modBy 2 >> (==) 1) [ 1, 2, 3, 4, 5, 6, 7 ]
--> 4

count
    ((==) "yeah")
    [ "She", "loves", "you", "yeah", "yeah", "yeah" ]
--> 3

Zipping

zip : List a -> List b -> List ( a, b )

Take two lists and returns a list of corresponding pairs

zip3 : List a -> List b -> List c -> List ( a, b, c )

Take three lists and returns a list of triples

Lift functions onto multiple lists of arguments

lift2 : (a -> b -> c) -> List a -> List b -> List c

Map functions taking multiple arguments over multiple lists, regardless of list length. All possible combinations will be explored.

lift2 (+) [1,2,3][4,5]
--> [5,6,6,7,7,8]

lift3 : (a -> b -> c -> d) -> List a -> List b -> List c -> List d

lift4 : (a -> b -> c -> d -> e) -> List a -> List b -> List c -> List d -> List e

Split to groups of given size

groupsOf : Basics.Int -> List a -> List (List a)

Split list into groups of length size. If there are not enough elements to completely fill the last group, it will not be included. This is equivalent to calling groupsOfWithStep with the same size and step.

groupsOf 3 (List.range 1 10)
--> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]

groupsOfWithStep : Basics.Int -> Basics.Int -> List a -> List (List a)

Split list into groups of length size at offsets step apart. If there are not enough elements to completely fill the last group, it will not be included. (See greedyGroupsOfWithStep if you would like the last group to be included regardless.)

groupsOfWithStep 4 4 (List.range 1 10)
--> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ] ]

groupsOfWithStep 3 1 (List.range 1 5)
--> [ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4, 5 ] ]

groupsOfWithStep 3 6 (List.range 1 20)
--> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ] ]

If step == size, every element (except for perhaps the last few due to the non-greedy behavior) will appear in exactly one group. If step < size, there will be an overlap between groups. If step > size, some elements will be skipped and not appear in any groups.

groupsOfVarying : List Basics.Int -> List a -> List (List a)

groupsOfVarying ns takes n elements from a list for each n in ns, splitting the list into variably sized segments

groupsOfVarying [ 2, 3, 1 ] [ "a", "b", "c", "d", "e", "f" ]
--> [ [ "a", "b" ], [ "c", "d", "e" ], [ "f" ] ]

groupsOfVarying [ 2 ] [ "a", "b", "c", "d", "e", "f" ]
--> [ [ "a", "b" ] ]

groupsOfVarying [ 2, 3, 1, 5, 6 ] [ "a", "b", "c", "d", "e" ]
--> [ [ "a", "b" ], [ "c", "d", "e" ] ]

greedyGroupsOf : Basics.Int -> List a -> List (List a)

Greedily split list into groups of length size. The last group of elements will be included regardless of whether there are enough elements in the list to completely fill it. This is equivalent to calling greedyGroupsOfWithStep with the same size and step.

greedyGroupsOf 3 (List.range 1 10)
--> [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ]

greedyGroupsOfWithStep : Basics.Int -> Basics.Int -> List a -> List (List a)

Greedily split list into groups of length size at offsets step apart. The last group of elements will be included regardless of whether there are enough elements in the list to completely fill it. (See groupsOfWithStep for the non-greedy version of this function).

greedyGroupsOfWithStep 4 4 (List.range 1 10)
--> [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ] ]

greedyGroupsOfWithStep 3 2 (List.range 1 6)
--> [ [ 1, 2, 3 ], [ 3, 4, 5 ], [ 5, 6 ] ]

greedyGroupsOfWithStep 3 6 (List.range 1 20)
--> [ [ 1, 2, 3 ], [ 7, 8, 9 ], [ 13, 14, 15 ], [ 19, 20 ] ]

If step == size, every element will appear in exactly one group. If step < size, there will be an overlap between groups. If step > size, some elements will be skipped and not appear in any groups.

Joins

joinOn : (a -> b -> c) -> (a -> comparable) -> (b -> comparable) -> List a -> List b -> List c

Performs an inner join, combining data items from both lists if they match by their respective key functions.

employees : List { name : String, departmentId : Int }
employees =
    [ { name = "Rafferty", departmentId = 31 }
    , { name = "Jones", departmentId = 33 }
    , { name = "Heisenberg", departmentId = 33 }
    , { name = "Robinson", departmentId = 34 }
    , { name = "Smith", departmentId = 34 }
    ]

departments : List { name : String, departmentId : Int }
departments =
    [ { departmentId = 31, name = "Sales" }
    , { departmentId = 33, name = "Engineering" }
    , { departmentId = 34, name = "Clerical" }
    , { departmentId = 35, name = "Marketing" }
    ]

joinOn (\empl dep -> { employee = empl.name, department = dep.name}) .departmentId .departmentId employees departments
--> [ { department = "Clerical", employee = "Robinson" }
--> , { department = "Clerical", employee = "Smith" }
--> , { department = "Engineering", employee = "Jones" }
--> , { department = "Engineering", employee = "Heisenberg" }
--> , { department = "Sales", employee = "Rafferty" }
--> ]

This is akin to the SQL query:

SELECT employee.name, department.name
FROM employee
INNER JOIN department
ON employee.departmentId = department.departmentId