basti1302 / elm-non-empty-array / Array.NonEmpty

An array that always contains at least one element.

Additionaly, it can track a currently selected index, which is guaranteed to point to an existing element in the array.

Most functions (like map) keep the currently selected index untouched, other functions (like filter or slice) discard the currently selected and reset it to zero. If not otherwise mentioned, the selected index is kept; if it is discarded, the function documentation states so explicitly.

Non Empty Array


type NonEmptyArray a

An array that is known, at compile-time, to be non empty. It always has at least one element.

Creation

fromElement : a -> NonEmptyArray a

Creates a new, non empty array with a single element. The selected index of the resulting array will be 0.

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

Initialize an array. initialize n f creates an array of length n with the element at index i initialized to the result of (f i).

When the requested number of elements is smaller than one (0 or negative), the returned array will still contain one element, f 0.

Just (initialize 4 identity) --> fromList [0, 1, 2, 3]

Just (initialize 4 (\n -> n * n)) --> fromList [0, 1, 4, 9]

Just (initialize 4 (always 0)) --> fromList [0, 0, 0, 0]

Just (initialize 0 identity) --> fromList [0]

The selected index of the resulting array will be 0.

repeat : Basics.Int -> a -> NonEmptyArray a

Creates an array with a given length, filled with a default element.

When the requested number of elements is smaller than one (0 or negative), this function will still return a non empty array with one element.

Just (repeat 5 0) --> fromList [0, 0, 0, 0, 0]

Just (repeat 3 "cat") --> fromList ["cat", "cat", "cat"]

Just (repeat 0 "frog") --> fromList ["frog"]

Notice that repeat 3 x is the same as initialize 3 (always x).

The selected index of the resulting array will be 0.

fromList : List a -> Maybe (NonEmptyArray a)

Create a NonEmptyArray from a List.

Given an empty list, this function will return Nothing. Given a list with at least one element, this function will return Just that list, converted to a NonEmptyArray.

The selected index of the resulting array will be 0.

fromArray : Array a -> Maybe (NonEmptyArray a)

Create a NonEmptyArray from an Array.

Given an empty array, this function will return Nothing. Given an array with at least one element, this function will return Just that array, converted to a NonEmptyArray.

The selected index of the resulting array will be 0.

Query

length : NonEmptyArray a -> Basics.Int

Return the length of the array.

get : Basics.Int -> NonEmptyArray a -> Maybe a

Return Just the element at the index or Nothing if the index is out of range.

get 0 (initialize 3 identity) --> Just 0

get 2 (initialize 3 identity) --> Just 2

get 5 (initialize 3 identity) --> Nothing

get -1 (initialize 3 identity) -->  Nothing

Notice that in contrast to mgold/elm-nonempty-list, where head and tail do not return Maybes, this function still necessarily returns a Maybe, because the given index can still be out of range. But see getFirst for a function that is known at compile time to return a value.

getFirst : NonEmptyArray a -> a

Return the first element of a NonEmptyArray.

getFirst (initialize 3 identity) --> 0

Manipulate

set : Basics.Int -> a -> NonEmptyArray a -> NonEmptyArray a

Set the element at a particular index. Returns an updated array. If the index is out of range, the array is unaltered.

set 0 1302 (fromElement 42) --> fromElement 1302

update : Basics.Int -> (a -> a) -> NonEmptyArray a -> NonEmptyArray a

Update the element at the given index using a function. Returns the array unchanged if the index is out of bounds.

Just <| update 1 ((+) 10) (initialize 3 identity)
--> fromList [0, 11, 2]

Just <| update 4 ((+) 10) (initialize 3 identity)
--> fromList [0, 1, 2]

Just <| update -1 ((+) 10) (initialize 3 identity)
--> fromList [0, 1, 2]

This is basically Array.Extra.update from elm-community/array-extra, for NonEmptyArray.

push : a -> NonEmptyArray a -> NonEmptyArray a

Push an element onto the end of an array.

Just (push 2 (fromElement 1)) --> fromList [1, 2]

append : NonEmptyArray a -> NonEmptyArray a -> NonEmptyArray a

Append two arrays to a new one.

Just (append (repeat 2 42) (repeat 3 81)) --> fromList [42, 42, 81, 81, 81]

The selected index of the resulting array will be the selected index of the first argument.

slice : Basics.Int -> Basics.Int -> NonEmptyArray a -> Maybe (NonEmptyArray a)

Get a sub-section of an array: (slice start end array). The start is a zero-based index where we will start our slice. The end is a zero-based index that indicates the end of the slice. The slice extracts up to but not including end. If the resulting slice would be empty, Nothing is returned.

slice 0 3 (initialize 5 identity) --> fromList [0, 1, 2]

slice 1 4 (initialize 5 identity) --> fromList [1, 2, 3]

slice 2 2 (initialize 5 identity) --> Nothing

Both the start and end indexes can be negative, indicating an offset from the end of the array.

slice 1 -1 (initialize 5 identity) --> fromList [1, 2, 3]

slice -2 5 (initialize 5 identity) --> fromList [3, 4]

This makes it pretty easy to pop the last element off of an array: slice 0 -1 array

The selected index will be set to 0 for the resulting array.

removeAt : Basics.Int -> NonEmptyArray a -> Maybe (NonEmptyArray a)

Removes the element at the given index.

removeAt 1 (initialize 4 identity) --> fromList [0, 2, 3]

If the index is out of range, the array is returned unchanged. If there is only one element in the array and index 0 is passed, Nothing will be returned. Otherwise, the element at the given index is removed.

If the removed element was the selected index, the selected index will be set to the previous element, or 0 if there is no previous element. Otherwise it will be updated so that the same element as before is selected.

removeAtSafe : Basics.Int -> NonEmptyArray a -> NonEmptyArray a

Removes the element at the given index.

Just (removeAtSafe 1 (initialize 4 identity)) --> fromList [0, 2, 3]

Just (removeAtSafe 0 (initialize 1 identity)) --> fromList [0]

If the index is out of range, the array is returned unchanged. If there is only one element left in the array, the array is also returned unchanged. Otherwise, the element at the given index is removed.

If the removed element was the selected index, the selected index will be set to the previous element, or 0 if there is no previous element. Otherwise it will be updated so that the same element as before is selected.

Selected Index

selectedIndex : NonEmptyArray a -> Basics.Int

Return the selected index.

repeat 5 "x"
    |> setSelectedIndex 3
    |> selectedIndex
--> 3

setSelectedIndex : Basics.Int -> NonEmptyArray a -> NonEmptyArray a

Set the selected index for the given array. If the index is out of range, the array is unaltered (that is, the old selected index is kept).

initialize 5 identity
    |> setSelectedIndex 2
    |> getSelected
--> 2

initialize 5 identity
    |> setSelectedIndex 7
    |> getSelected
--> 0

setSelectedIndexAndReport : Basics.Int -> NonEmptyArray a -> ( NonEmptyArray a, Basics.Bool )

Set the selected index for the given array and reports if an index change actually happened. If the index is out of range, the array is unaltered (that is, the old selected index is kept).

The second value of the returned tuple is True if and only if the index actually changed due to the operation. False is returned if you pass in an index that is out of range, or when you pass in the index that is currently selected anyway.

initialize 5 identity
|> setSelectedIndexAndReport 2
|> Tuple.second
--> True

initialize 5 identity
|> setSelectedIndexAndReport 7
|> Tuple.second
--> False

initialize 5 identity
|> setSelectedIndexAndReport 0
|> Tuple.second
--> False

getSelected : NonEmptyArray a -> a

Return the element at the selected index.

initialize 3 identity
    |> setSelectedIndex 1
    |> getSelected
--> 1

updateSelected : (a -> a) -> NonEmptyArray a -> NonEmptyArray a

Update the element at the current selected index using a function.

Just <| updateSelected ((+) 10) (initialize 3 identity)
--> fromList [10, 1, 2]

mapSelected : (Basics.Bool -> a -> b) -> NonEmptyArray a -> NonEmptyArray b

Apply a function to every element in an array. The first argument to that function is a Boolean that is True for the selected element. This makes it easier to treat the select element different from other elements.

Just <|
  (repeat 5 1
    |> mapSelected (\isSelected ->
      if isSelected then
        (*) 2
      else
        Basics.identity
    ))
  --> fromList [2, 1, 1, 1, 1]

indexedMapSelected : (Basics.Bool -> Basics.Int -> a -> b) -> NonEmptyArray a -> NonEmptyArray b

Apply a function to every element in an array. The first argument to that function is a Boolean that is True for the selected element. This makes it easier to treat the select element different from other elements. The second argument is the element's index.

Just <|
  (repeat 5 1
    |> indexedMapSelected (\isSelected ->
      if isSelected then
        (*)
      else
        (+)
    ))
  --> fromList [0, 2, 3, 4, 5]

Conversions

toArray : NonEmptyArray a -> Array a

Converts the NonEmptyArray into a standard array.

import Array

fromArray (Array.fromList [1, 2])
    |> Maybe.map toArray
--> Just (Array.fromList [1, 2])

toList : NonEmptyArray a -> List a

Create a list of elements from an array.

fromList [3, 5, 8]
    |> Maybe.map toList
--> Just [3, 5, 8]

toIndexedList : NonEmptyArray a -> List ( Basics.Int, a )

Create an indexed list from an array. Each element of the array will be paired with its index.

fromList ["cat", "dog"]
    |> Maybe.map toIndexedList
--> Just [(0, "cat"), (1, "dog")]

Transform

foldl : (a -> b -> b) -> b -> NonEmptyArray a -> b

Reduce an array from the left. Read foldl as fold from the left.

foldl (::) [] (initialize 3 identity) --> [2, 1, 0]

foldr : (a -> b -> b) -> b -> NonEmptyArray a -> b

Reduce an array from the right. Read foldr as fold from the right.

foldr (+) 0 (repeat 3 5) --> 15

filter : (a -> Basics.Bool) -> NonEmptyArray a -> Maybe (NonEmptyArray a)

Keep only elements that satisfy the predicate. If no elements remain, Nothing is returned, otherwise Just the array of remaining elements.

isEven : Int -> Bool
isEven n =
    Basics.modBy 2 n == 0

filter isEven (initialize 5 identity) --> fromList [0, 2, 4]

The selected index will be set to 0 for the resulting array.

map : (a -> b) -> NonEmptyArray a -> NonEmptyArray b

Apply a function to every element in an array.

map Debug.toString (repeat 5 1) --> repeat 5 "1"

indexedMap : (Basics.Int -> a -> b) -> NonEmptyArray a -> NonEmptyArray b

Apply a function to every element with its index as first argument.

Just (indexedMap (*) (repeat 5 2)) --> fromList [0, 2, 4, 6, 8]

JSON Decoding/Encoding

decoder : Json.Decode.Decoder a -> Json.Decode.Decoder (NonEmptyArray a)

Decodes a JSON array into a NonEmptyArray. Produces a Decode.fail for an empty JSON array.

decoderWithDefault : Json.Decode.Decoder a -> a -> Json.Decode.Decoder (NonEmptyArray a)

Decodes a JSON array into a NonEmptyArray. Returns a NonEmptyArray with the given default value as its only element when decoding an empty JSON array.

encode : (a -> Json.Encode.Value) -> NonEmptyArray a -> Json.Encode.Value

Turns a NonEmptyArray into a JSON array. Each element will be encoded with the provided encoding function.