lue-bird / elm-linear-direction / Array.Linear

Array operations that can be applied in either Direction

scan

element : ( Linear.Direction, Basics.Int ) -> Array element -> Maybe element

The element at a given index in a given Direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ "lose", "win", "lose" ]
    |> Array.Linear.element ( Down, 0 )
--> Just "lose"

Array.fromList [ "lose", "win", "lose" ]
    |> Array.Linear.element ( Up, 0 )
--> Just "lose"

Nothing if the index is out of range

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.element ( Up, -1 )
--> Nothing

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.element ( Up, 100 )
--> Nothing

transform

foldFrom : accumulationValue -> Linear.Direction -> (element -> accumulationValue -> accumulationValue) -> Array element -> accumulationValue

Reduce in a given Direction from a given initial accumulated thing

import Linear exposing (Direction(..))
import Array

Array.fromList [ 'l', 'i', 'v', 'e' ]
    |> Array.Linear.foldFrom "" Up String.cons
--> "evil"

Array.fromList [ 'l', 'i', 'v', 'e' ]
    |> Array.Linear.foldFrom "" Down String.cons
--> "live"

mapFoldFrom : accumulationValue -> Linear.Direction -> ({ element : element, folded : accumulationValue } -> { element : mappedElement, folded : accumulationValue }) -> Array element -> { mapped : Array mappedElement, folded : accumulationValue }

Map each element using information collected from previous steps, folding in a given Direction from given initial information.

Both the mapped Array and the folded information will be returned

You'll often find this under the name "mapAccum"

import Linear exposing (Direction(..))
import Array exposing (Array)

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.mapFoldFrom 0
        Down
        (\state ->
            { element = state.folded
            , folded = state.folded + state.element
            }
        )
--> { mapped = Array.fromList [ 5, 3, 0 ], folded = 6 }

mapIndexed : Direction -> (Int -> a -> b) -> (Array a -> Array b)
mapIndexed indexDirection mapAtIndex =
    Array.Linear.mapFoldFrom 0
        indexDirection
        (\state ->
            { element = state.element |> mapAtIndex state.folded
            , folded = state.folded + 1
            }
        )
        >> .mapped

Array.fromList [ 'h', 'i', 'y', 'o' ]
    |> mapIndexed Up Tuple.pair
--> Array.fromList [ ( 0, 'h' ), ( 1, 'i' ), ( 2, 'y' ), ( 3, 'o' ) ]

Array.fromList [ 'h', 'i', 'y', 'o' ]
    |> mapIndexed Down Tuple.pair
--> Array.fromList [ ( 3, 'h' ), ( 2, 'i' ), ( 1, 'y' ), ( 0, 'o' ) ]

alter

elementReplace : ( Linear.Direction, Basics.Int ) -> (() -> element) -> Array element -> Array element

Set the element at a given index in a given Direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ "I", "am", "ok" ]
    |> Array.Linear.elementReplace ( Up, 2 )
        (\() -> "confusion")
--> Array.fromList [ "I", "am", "confusion" ]

Array.fromList [ "I", "am", "ok" ]
    |> Array.Linear.elementReplace ( Down, 1 )
        (\() -> "feel")
--> Array.fromList [ "I", "feel", "ok" ]

If the index is out of range, the Array is unaltered

import Linear exposing (Direction(..))
import Array

Array.fromList [ "I", "am", "ok" ]
    |> Array.Linear.elementReplace ( Up, -1 )
        (\() -> "is")
--> Array.fromList [ "I", "am", "ok" ]

elementAlter : ( Linear.Direction, Basics.Int ) -> (element -> element) -> Array element -> Array element

Change the element at a given index in a given Direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ "I", "am", "ok" ]
    |> Array.Linear.elementAlter ( Up, 2 )
        String.toUpper
--> Array.fromList [ "I", "am", "OK" ]

Array.fromList [ "I", "am", "ok" ]
    |> Array.Linear.elementAlter ( Down, 0 )
        String.toUpper
--> Array.fromList [ "I", "am", "OK" ]

If the index is out of range, the Array is unaltered

import Linear exposing (Direction(..))
import Array

Array.fromList [ "I", "am", "ok" ]
    |> Array.Linear.elementAlter ( Up, -1 )
        String.toUpper
--> Array.fromList [ "I", "am", "ok" ]

insert : ( Linear.Direction, Basics.Int ) -> (() -> element) -> Array element -> Array element

Put in a given element at a given index in a given Direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ 'a', 'c', 'd' ]
    |> Array.Linear.insert ( Up, 1 )
        (\() -> 'b')
--> Array.fromList [ 'a', 'b', 'c', 'd' ]

Array.fromList [ 'a', 'c', 'd' ]
    |> Array.Linear.insert ( Down, 2 )
        (\() -> 'b')
--> Array.fromList [ 'a', 'b', 'c', 'd' ]

If the index is out of bounds, nothing is inserted

import Linear exposing (Direction(..))
import Array

Array.fromList [ 'a', 'c', 'd' ]
    |> Array.Linear.insert ( Up, -1 )
        (\() -> 'b')
--> Array.fromList [ 'a', 'c', 'd' ]

Array.fromList [ 'a', 'c', 'd' ]
    |> Array.Linear.insert ( Up, 4 )
        (\() -> 'b')
--> Array.fromList [ 'a', 'c', 'd' ]

squeezeIn allows inserting a whole Array of elements

remove : ( Linear.Direction, Basics.Int ) -> Array element -> Array element

Kick an element out at a given index in a given Direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ 'a', 'a', 'b' ]
    |> Array.Linear.remove ( Up, 1 )
--> Array.fromList [ 'a', 'b' ]

Array.fromList [ 'a', 'b', 'c', 'd' ]
    |> Array.Linear.remove ( Down, 0 )
--> Array.fromList [ 'a', 'b', 'c' ]

If the index is out of bounds, nothing is changed

import Linear exposing (Direction(..))
import Array

Array.fromList [ 'a', 'a', 'b' ]
    |> Array.Linear.remove ( Up, -1 )
--> Array.fromList [ 'a', 'a', 'b' ]

Array.fromList [ 'a', 'a', 'b' ]
    |> Array.Linear.remove ( Up, 100 )
--> Array.fromList [ 'a', 'a', 'b' ]

padToAtLeast : Linear.Direction -> Basics.Int -> (Basics.Int -> Array element) -> Array element -> Array element

Pad in a Direction based on how much it takes to reach at a given length

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2 ]
    |> Array.Linear.padToAtLeast Up
        4
        (\l -> Array.repeat l 0)
--> Array.fromList [ 1, 2, 0, 0 ]

Array.fromList [ 1, 2 ]
    |> Array.Linear.padToAtLeast Down
        4
        (\l -> Array.repeat l 0)
--> Array.fromList [ 0, 0, 1, 2 ]

To achieve "resize" behavior, use padToAtLeast direction length followed by take direction length

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.padToAtLeast Up
        2
        (\l -> Array.repeat l 0)
    |> Array.Linear.take Up 2
--> Array.fromList [ 1, 2 ]

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.padToAtLeast Down
        2
        (\l -> Array.repeat l 0)
    |> Array.Linear.take Down 2
--> Array.fromList [ 2, 3 ]

part

take : Linear.Direction -> Basics.Int -> Array element -> Array element

A given number of elements from one side in a given Direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2, 3, 4, 5, 6 ]
    |> Array.Linear.take Up 4
    |> Array.Linear.take Down 2
--> Array.fromList [ 3, 4 ]

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.take Up 100
--> Array.fromList [ 1, 2, 3 ]

The amount of elements to take is negative? → Array.empty

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.take Up -100
--> Array.empty

drop : Linear.Direction -> Basics.Int -> Array element -> Array element

Remove a given number of elements from one side

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2, 3, 4, 5, 6 ]
    |> Array.Linear.drop Down 2
--> Array.fromList [ 1, 2, 3, 4 ]

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.drop Up 100
--> Array.empty

Nothing is dropped if the amount of elements to drop is negative

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.drop Up -1
--> Array.fromList [ 1, 2, 3 ]

toChunksOf : Linear.Direction -> Basics.Int -> Array element -> { chunks : Array (Array element), remainder : Array element }

Split into equal-sized chunks of a given length in a given Direction. The left over elements to one side are in remainder

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2, 3, 4, 5, 6, 7 ]
    |> Array.Linear.toChunksOf Up 3
--> { chunks =
-->     Array.fromList
-->         [ Array.fromList [ 1, 2, 3 ]
-->         , Array.fromList [ 4, 5, 6 ]
-->         ]
--> , remainder = Array.fromList [ 7 ]
--> }

Array.fromList [ 1, 2, 3, 4, 5, 6, 7 ]
    |> Array.Linear.toChunksOf Down 3
--> { remainder = Array.fromList [ 1 ]
--> , chunks =
-->     Array.fromList
-->         [ Array.fromList [ 2, 3, 4 ]
-->         , Array.fromList [ 5, 6, 7 ]
-->         ]
--> }

glueing

attach : Linear.Direction -> Array element -> Array element -> Array element

Attach elements of a given Array to the end in a given direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.attach Up (Array.fromList [ 4, 5, 6 ])
--> Array.fromList [ 1, 2, 3, 4, 5, 6 ]

Array.fromList [ 1, 2, 3 ]
    |> Array.Linear.attach Down (Array.fromList [ 4, 5, 6 ])
--> Array.fromList [ 4, 5, 6, 1, 2, 3 ]

squeezeIn : ( Linear.Direction, Basics.Int ) -> (() -> Array element) -> Array element -> Array element

Put elements of a given Array between the elements left and right to the given index in a given Direction

import Linear exposing (Direction(..))
import Array

Array.fromList [ 'a', 'd', 'e' ]
    |> Array.Linear.squeezeIn ( Up, 1 )
        (\() -> Array.fromList [ 'b', 'c' ])
--> Array.fromList [ 'a', 'b', 'c', 'd', 'e' ]

Array.fromList [ 'a', 'd', 'e' ]
    |> Array.Linear.squeezeIn ( Down, 2 )
        (\() -> Array.fromList [ 'b', 'c' ])
--> Array.fromList [ 'a', 'b', 'c', 'd', 'e' ]

If the index is outside of the Array's range, nothing is inserted

import Linear exposing (Direction(..))
import Array

Array.fromList [ 'a', 'd', 'e' ]
    |> Array.Linear.squeezeIn ( Up, -1 )
        (\() -> Array.fromList [ 'b', 'c' ])
--> Array.fromList [ 'a', 'd', 'e' ]

Array.fromList [ 'a', 'd', 'e' ]
    |> Array.Linear.squeezeIn ( Up, 4 )
        (\() -> Array.fromList [ 'b', 'c' ])
--> Array.fromList [ 'a', 'd', 'e' ]

insert allows inserting a single element