The List.Nonempty.Ancillary module provides additional convenience
functions not found in mgold/elm-nonempty-list for dealing with non-empty
lists.
Given an index and an update function, replace the value at that index
by calling the update function. Indices are modulus the length of the list, so
out-of-range errors cannot occur; this means that negative indices are
supported, e.g. -1 to update the last element. This is consistent with the
behavior of List.Nonempty.get
Note that this is not particularly efficient (iterating over the entire list
multiple times) and should probably not be used for very large lists. Arrays
are of course preferable in such cases.
import List.Nonempty exposing (Nonempty(..))
updateAt 1 ((+) 1) <| Nonempty 1 [ 1, 1 ]
--> Nonempty 1 [ 2, 1 ]
updateAt 6 ((+) 1) <| Nonempty 1 [ 1, 1 ]
--> Nonempty 2 [ 1, 1 ]
updateAt -1 ((+) 1) <| Nonempty 1 [ 1, 1 ]
--> Nonempty 1 [ 1, 2 ]Append a list to the end of a non-empty list.
import List.Nonempty exposing (Nonempty(..))
appendList (Nonempty 1 [ 2 ]) [ 3, 4 ]
--> Nonempty 1 [ 2, 3, 4 ]
appendList (Nonempty 1 [ 2 ]) []
--> Nonempty 1 [ 2 ]Prepend a list to the beginning of a non-empty list.
import List.Nonempty exposing (Nonempty(..))
prependList [ 1, 2 ] <| Nonempty 3 [ 4 ]
--> Nonempty 1 [ 2, 3, 4 ]
prependList [] <| Nonempty 1 [ 2 ]
--> Nonempty 1 [ 2 ]Initialize a list of a given length by calling a function with each index. The resulting list will always have at least 1 item, even if called with a negative or zero length.
import List.Nonempty exposing (Nonempty(..))
initialize 1 (\i -> i)
--> Nonempty 0 []
initialize 3 (\i -> i * 2)
--> Nonempty 0 [ 2, 4 ]
initialize 0 (\i -> i + 1)
--> Nonempty 1 []
initialize -1 (\i -> i + 1)
--> Nonempty 1 []Reduce a non-empty list from the right.
import List.Nonempty exposing (Nonempty(..))
foldr (+) 0 <| Nonempty 1 [ 2, 3 ]
--> 6
foldr (::) [] <| Nonempty 1 [ 2, 3 ]
--> [ 1, 2, 3 ]Reduce a non-empty list from the right, treating the last element of the list as the starting value.
import List.Nonempty exposing (Nonempty(..))
foldr1 (-) <| Nonempty 1 [ 2, 3, 4 ]
--> -2
foldr1 (++) <| Nonempty "a" [ "b", "c" ]
--> "abc"Find minimum/maximum elements without Maybes.
Find the maximum element in a non-empty list.
import List.Nonempty exposing (Nonempty(..))
maximum <| Nonempty 1 [ 3, 2 ]
--> 3Given a function to map a type to a comparable type, find the first maximum element in a non-empty list.
import List.Nonempty exposing (Nonempty(..))
maximumBy (\i -> i * i) <| Nonempty 1 [ -3, 3 ]
--> -3Given a comparison function, find the first maximum element in a non-empty list.
import List.Nonempty exposing (Nonempty(..))
Nonempty { id = 0, val = 1 } [ { id = 1, val = 3 }, { id = 2, val = 0 } ]
|> maximumWith (\a b -> compare a.val b.val)
--> { id = 1, val = 3 }Find the minimum element in a non-empty list.
import List.Nonempty exposing (Nonempty(..))
minimum <| Nonempty 1 [ 3, 2 ]
--> 1Given a function to map a type to a comparable type, find the first minimum element in a non-empty list.
import List.Nonempty exposing (Nonempty(..))
minimumBy (\i -> i * i) <| Nonempty 1 [ -1, 2 ]
--> 1Given a comparison function, find the first minimum element in a non-empty list.
import List.Nonempty exposing (Nonempty(..))
Nonempty { id = 0, val = 1 } [ { id = 1, val = 3 }, { id = 2, val = 0 } ]
|> minimumWith (\a b -> compare a.val b.val)
--> { id = 2, val = 0 }Find minimum/maximum elements and their indices without Maybes.
Find the first maximum element in a non-empty list and its index.
import List.Nonempty exposing (Nonempty(..))
indexedMaximum <| Nonempty 1 [ 3, 2, 3 ]
--> ( 1, 3 )Given a function to map a type to a comparable type, find the first maximum element in a non-empty list and its index.
import List.Nonempty exposing (Nonempty(..))
indexedMaximumBy (\i -> i * i) <| Nonempty 1 [ -3, 3 ]
--> ( 1, -3 )Given a comparison function, find the first maximum element in a non-empty list and its index.
import List.Nonempty exposing (Nonempty(..))
Nonempty { id = 0, val = 1 } [ { id = 1, val = 3 }, { id = 2, val = 3 } ]
|> indexedMaximumWith (\a b -> compare a.val b.val)
--> ( 1, { id = 1, val = 3 } )Find the first minimum element in a non-empty list and its index.
import List.Nonempty exposing (Nonempty(..))
indexedMinimum <| Nonempty 2 [ 2, 1, 1 ]
--> ( 2, 1 )Given a function to map a type to a comparable type, find the first minimum element in a non-empty list and its index.
import List.Nonempty exposing (Nonempty(..))
indexedMinimumBy (\i -> i * i) <| Nonempty 2 [ -1, 1 ]
--> ( 1, -1 )Given a comparison function, find the first minimum element in a non-empty list and its index.
import List.Nonempty exposing (Nonempty(..))
Nonempty { id = 0, val = 1 } [ { id = 1, val = 3 }, { id = 2, val = 1 } ]
|> indexedMinimumWith (\a b -> compare a.val b.val)
--> ( 0, { id = 0, val = 1 } )Find the first element that satisfies a predicate and return Just that
element, or if none match, return Nothing.
import List.Nonempty exposing (Nonempty(..))
find (\i -> i > 3) <| Nonempty 2 [ 4, 6, 8 ]
--> Just 4
find (\i -> i > 3) <| Nonempty 0 [ 1, 2, 3 ]
--> NothingReturn the number of elements in the list that satisfy a given predicate.
import List.Nonempty exposing (Nonempty(..))
count ((==) Nothing << String.toInt) <| Nonempty "1" [ "yi", "2", "er", "3", "san" ]
--> 3MaybesIf every Maybe in the non-empty list is Just a, then return a list of
all the unwrapped values. If one or more elements are Nothing, then the
entire output will be Nothing.
import List.Nonempty exposing (Nonempty(..))
combine (Nonempty (Just 1) [ Just 2, Just 3 ])
--> Just (Nonempty 1 [ 2, 3 ])
combine (Nonempty (Just 1) [ Nothing, Just 3 ])
--> NothingMap a function over every element in the non-empty list. If every function
call returns Just a, then return a list of all the values. If one or more
function call returns Nothing, then the entire output will be Nothing.
import List.Nonempty exposing (Nonempty(..))
traverse List.head (Nonempty [ 1 ] [ [2], [ 3, 4 ] ])
--> Just (Nonempty 1 [ 2, 3 ])
traverse List.head (Nonempty [ 1 ] [ [], [ 3, 4 ] ])
--> NothingThe module provides two sets of JSON decoder/encodes. In the first,
decodeArray/encodeArray, the non-empty list is represented as a standard
JSON array. Decoding an empty array will fail, and encoding to an empty array
will never happen.
In the second, decodeObject/encodeObject, the non-empty list is explicitly
represented as an object with two keys: "head" (containing the first element)
and "tail", containing a (possibly empty) array of the rest of the elements:
{ "head": x1
, "tail": [x2, x3]
}Decode a non-empty list from a JSON array, failing if it is empty.
import List.Nonempty exposing (Nonempty(..))
import Json.Decode as Decode
Decode.decodeString (decodeArray Decode.int) "[1,2,3]"
--> Ok (Nonempty 1 [ 2, 3 ])
Decode.decodeString (decodeArray Decode.int) "[]"
|> Result.toMaybe
--> NothingTurn a non-empty list into a JSON array.
import List.Nonempty exposing (Nonempty(..))
import Json.Encode as Encode
Encode.encode 0 (encodeArray Encode.int <| Nonempty 1 [ 2, 3 ])
--> "[1,2,3]"Decode a non-empty list from a JSON object of the form:
{ "head": x1
, "tail": [x2, x3]
}
import List.Nonempty exposing (Nonempty(..))
import Json.Decode as Decode
Decode.decodeString (decodeObject Decode.int) "{ \"head\": 1, \"tail\": [2,3] }"
--> Ok (Nonempty 1 [ 2, 3 ])Encode a non-empty list into a JSON object of the form:
{ "head": x1
, "tail": [x2, x3]
}
import List.Nonempty exposing (Nonempty(..))
import Json.Encode as Encode
Encode.encode 0 (encodeObject Encode.int <| Nonempty 1 [ 2, 3 ])
--> "{\"head\":1,\"tail\":[2,3]}"Shuffle the non-empty list. This of course has no effect on a list of one element.
Given a non-empty list random generators, turn them into a generator that returns a non-empty list.
Given an index and a value, replace the element at that index with the given value. Indices are modulus the length of the list, so out-of-range errors cannot occur; this means that negative indices are supported, e.g. -1 to set the last element. This is consistent with the behavior of
List.Nonempty.getNote that this is not particularly efficient (iterating over the entire list multiple times) and should probably not be used for very large lists.
Arrays are of course preferable in such cases.