Giter Site home page Giter Site logo

elm-community / array-extra Goto Github PK

View Code? Open in Web Editor NEW
9.0 7.0 10.0 620 KB

convenience functions for working with Array

Home Page: http://package.elm-lang.org/packages/elm-community/array-extra/latest

License: MIT License

Elm 100.00%
array elm extra elm-core

array-extra's Introduction

convenience functions for working with Array

Some people like to import under the same namespace as Array:

import Array exposing (Array)
import Array.Extra as Array

firstFive : Array a -> Array a
firstFive =
    Array.sliceUntil 5

Note that this API is experimental and likely to go through many more iterations.

Feedback and contributions are very welcome.

array-extra's People

Contributors

agrafix avatar alienkevin avatar dependabot[bot] avatar indique avatar jonboiser avatar lue-bird avatar martinsstewart avatar prikhi avatar rehno-lindeque avatar robinheghan avatar sindikat avatar skinney avatar turbomack avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

array-extra's Issues

Bug with resizerRepeat

Try this code

import Graphics.Element exposing (show)
import Array exposing (Array)
import Array.Extra

a = Array.fromList [0..9]

x = Array.Extra.resizelRepeat 3 500 a
y = Array.Extra.resizelRepeat 12 750 a
z = Array.Extra.resizerRepeat 3 1000 a

main = show <| z

z equals [9,750,750]. Now run the following code:

import Graphics.Element exposing (show)
import Array exposing (Array)
import Array.Extra

a = Array.fromList [0..9]

-- x = Array.Extra.resizelRepeat 3 500 a
-- y = Array.Extra.resizelRepeat 12 750 a
z = Array.Extra.resizerRepeat 3 1000 a

main = show <| z

z equals [7,8,9].

Apparently, something going on with an array on the JavaScript side. This bug most likely has to do with upstream, but I am not sure at all how to narrow this bug down yet.

All I know it has to do with Array.repeat or Array.append, because this bug happens only when the code

xs `append` repeat (n - l) val

is activated inside resizelRepeat body (code line).

Add Array.insert

Insert an element to an array at a specific index (can be negative).

insert : Int -> a -> Array a -> Array a
insert i el arr =
  Array.append
  ( Array.push el <|
    Array.slice 0 i arr
  )
  (Array.slice i (Array.length arr) arr)

Check out sample tests on Ellie

renaming suggestions

To improve consistency

  • sliceUntil โ†’ take
    • ๐Ÿ‘ like List.drop for natural indexes
    • ๐Ÿ‘Ž unlike List.drop for negative indexes
  • sliceFrom โ†’ drop
    • ๐Ÿ‘ like List.take for natural indexes
    • ๐Ÿ‘Ž unlike List.take for negative indexes
  • update โ†’ updateAt
    • ๐Ÿ‘ like Array.Extra.removeAt, Array.Extra.insertAt, Array.Extra.splitAt
    • ๐Ÿ‘Ž unlike Array.get, Array.set

Array.member

Should we add something like this?

{-| To check if array contains value.
-}
member : a -> Array a -> Bool
member needle haystack =
    Array.foldr (\item acc -> acc || item == needle) False haystack

Adding Array.unzip

Since we have zip, shall we add an unzip?

unzip : Array (a, b) -> (Array a, Array b)
unzip arrAB =
  Array.foldl
    (\(a, b) (arrA, arrB) ->
      (Array.push a arrA, Array.push b arrB)
    )
    (Array.empty, Array.empty)
    arrAB

add `indexedFilterMap`

Implement indexedFilterMap : (Int -> a -> Maybe b) -> ... as a more performant and convenient alternative to

Array.indexedMap Tuple.pair
    |> Array.filterMap (\( i, el ) -> ...)

a "findAll" would then be trivial

Array.filterMapIndexed (\i el -> ...)

Related: #12

Get/set that take negative arguments?

Array.get and Array.set return Nothing if given negative argument. (See also core's Native/Array.js).

There might be reasons to leave this behavior as is. For example, current get semantics allow you to countdown and once you hit Nothing, you know that you fully traversed the array right to left, IOW, you did hit the left edge of the array. Do people use that kind of behavior?

I, coming from Python, think, however, that Array.get and Array.set supporting negative arguments make them much more versatile and convenient to use. Negative arguments mean you can get or set from the end of the array. Again, if lists's length is 5, you can't have below -5 as an argument, as this also constitutes index-out-of-bound.

I use my variant of Array.get all the time now, and this is how I defined it in Elm:

get2 : Int -> Array a -> Maybe a
get2 n a =
  let
    len = Array.length a
  in
    if n < 0 && abs n <= len
    then Array.get (len + n) a
    else Array.get n a

I however think it should be defined on the level of Native/Array.js in the core some day. I also plan to write set and update versions of this too.

My question is, do you want that function in Array.Extra? And how should we call it? I think it's safe to call it just get, because there won't be any namespace collision (Array.get against Array.Extra.get), and people will notice from the namespace, that these functions might have slightly different behavior. Also there's chance this function would be added into the core.

Do you agree? If not, what name could we give to a variant of Array.get that accepts negative arguments?

Documentation for mapToList is weird

The documentation for mapToList is the following

{-| Apply a function to the elements in the array and collect the result in a List.

    Html.text : String -> Html msg
    mapToList Html.text : Array String -> List (Html msg)
-}

I believe that the first line is alright, but I don't think the remaining lines make much sense, and it almost feels like a copy-paste gone wrong.

I would have expected to see an example of mapToList usage, with the input and output.

EDIT: Ok, maybe I now see it. The thing on the left of : are values and what's on the right is the type, just like a REPL.

I think the style of the example is inconsistent with the rest of the examples in the package. I think something like this would be more helpful

    mapToList
		String.fromInt
        (fromList [ 1, 2, 3 ])
        == [ "1", "2", "3" ]

Side-note: Instead of using ==, you could use https://github.com/stoeffel/elm-verify-examples to make sure the examples are always correct.

Some sample tests for removeAt

Feel free to use this or ignore and close. I wrote some tests for a function called "removeByIndex" which is similar to "removeAt"

module Tests.Array.Extra exposing (all)

import Array
import Array.Extra exposing (removeByIndex, withDefault)
import Expect
import Test exposing (Test, describe, test)


all : Test
all =
    describe "all"
        [ describe "removeByIndex"
            [ test "typical usage" <|
                \_ ->
                    Expect.equal
                        (Array.fromList [ 0, 2 ])
                        (removeByIndex 1 (Array.fromList [ 0, 1, 2 ]))
            , test "handles first element deletion" <|
                \_ ->
                    Expect.equal
                        (Array.fromList [ 1, 2 ])
                        (removeByIndex 0 (Array.fromList [ 0, 1, 2 ]))
            , test "handles last element deletion" <|
                \_ ->
                    Expect.equal
                        (Array.fromList [ 0, 1 ])
                        (removeByIndex 2 (Array.fromList [ 0, 1, 2 ]))
            , test "ignores index out of bounds - too large" <|
                \_ ->
                    Expect.equal
                        (Array.fromList [ 0, 1, 2 ])
                        (removeByIndex 5 (Array.fromList [ 0, 1, 2 ]))
            , test "ignores index out of bounds - too small - empty" <|
                \_ ->
                    Expect.equal
                        Array.empty
                        (removeByIndex -1 Array.empty)
            , test "undefined behavior when index out of bounds - too small - non empty" <|
                \_ ->
                    Expect.notEqual
                        (Array.fromList [ 0, 1, 2 ])
                        (removeByIndex -1 (Array.fromList [ 0, 1, 2 ]))
            ]
        ]

Evaluation of short circuit versions of any and all

I got curious as whether or not any and all short circuits, see https://discourse.elm-lang.org/t/how-does-array-extra-all-short-circuit/8947, and it seems like the current implementations does not short circuit.

I've found #26 where it says that the implementation with List.foldl was the fastest. I've tried to search the repository for various implementation candidates and maybe you already evaluated a version of any similar to this which short circuits on the first True?

any isOkay array =
    let
        step index =
            case Array.get index array |> Maybe.map isOkay of
                Just True ->
                    True

                Just False ->
                    step (index + 1)

                Nothing ->
                    False
    in
    step 0

sorting

I miss sorting operations like sort, sortBy & sortWith in List the most when working with arrays.
I think these would be worth adding to elm/core's Array module. Until anything gets decided, array-extra could just copy Lists sorting API:

sortWith : (a -> a -> Order) -> Array a -> Array a
sortWith elementOrder array =
    array
        |> Array.toList
        |> List.sortWith elementOrder
        |> Array.fromList

-- same with sort & sortBy

An example use-case is finding an Arrays 5 biggest numbers.

Array.find is missing?

Hi!

I'm curious why there is no find function either in core or here in extras?
I literally checked both three times, because I thought it's just me being blind
Wouldn't that be a useful addition?

find : (a -> Bool) -> Array a -> Maybe a

Also it would be natural to have its findLast counterpart
Maybe even call find as findFirst for clarity?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.