elm-community / list-extra

Convenience functions for working with List.
http://package.elm-lang.org/packages/elm-community/list-extra/latest
MIT License
135 stars 58 forks source link

Proposal for `splitsAt` function #100

Open EverybodyKurts opened 6 years ago

EverybodyKurts commented 6 years ago

It would be defined something like this:

{-| 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)`.

    splitsAt [2,3] [1,2,3,4,5] == [[1,2],[3],[4,5]]
    splitsAt [2,4] [1,2,3,4,5,6] == [[1,2],[3,4],[5,6]]
    splitsAt [1,2,4] [1,2,3,4,5,6] == [[1],[2],[3,4],[5,6]]
    splitsAt [1] [1,2,3] == [[1],[2,3]]
    splitsAt [3] [1,2,3] == [[1,2,3],[]]
    splitsAt [0] [1,2,3] == [[],[1,2,3]]
    splitsAt [] [1,2,3] == [[1,2,3]]
-}
splitsAt : List Int -> List a -> List (List a)
splitsAt indices list =
    let
        sa : List Int -> List a -> List (List a) -> List (List a)
        sa indices list splits =
            case uncons indices of
                Just ( index, restIndices ) ->
                    let
                        ( split, rest ) =
                            splitAt index list

                        splitLength =
                            List.length split

                        adjustedRestIndices =
                            restIndices
                                |> List.map (flip (-) splitLength)
                    in
                        sa adjustedRestIndices rest (splits ++ [ split ])

                Nothing ->
                    splits ++ [ list ]
    in
        sa indices list []

I'd be more than happy to create a merge request using the module formatting for documentation and the like. Let me know.

pzp1997 commented 6 years ago

This seems very similar to List.Extra.groupsOfVarying. Do you have some specific use-case in mind for which that function is not sufficient?

EverybodyKurts commented 6 years ago

I believe there are some slight differences between groupsOfVarying and my proposed splitsAt function. groupsOfVarying specifies the length of each group while splitsAt specifies the index of where the split should end. groupsOfVarying can return a list of lists that doesn't necessarily include all elements in the original list while splitsAt does include all elements in the original list.

I haven't tested splitsAt with list of indices like [3,2,1] or [1,1,1].

Chadtech commented 6 years ago

Im not seeing the value in this function to be honest. Assuming good code practices were used, I dont know how you could end up in a circumstance where you could know which indices you want to split at without also having access to the elements you are trying to split.