List split in Elm

Viewed 362

Write a function to split a list into two lists. The length of the first part is specified by the caller.

I am new to Elm so I am not sure if my reasoning is correct. I think that I need to transform the input list in an array so I am able to slice it by the provided input number. I am struggling a bit with the syntax as well. Here is my code so far:

listSplit: List a -> Int -> List(List a)
listSplit inputList nr = 
let myArray = Array.fromList inputList
    in Array.slice 0 nr myArray 

So I am thinking to return a list containing 2 lists(first one of the specified length), but I am stuck in the syntax. How can I fix this?

3 Answers

Alternative implementation:

split : Int -> List a -> (List a, List a)
split i xs =
    (List.take i xs, List.drop i xs) 

I'll venture a simple recursive definition, since a big part of learning functional programming is understanding recursion (which foldl is just an abstraction of):

split : Int -> List a -> (List a, List a)
split splitPoint inputList =
    splitHelper splitPoint inputList []

{- We use a typical trick here, where we define a helper function 
that requires some additional arguments. -}
splitHelper : Int -> List a -> List a -> (List a, List a)
splitHelper splitPoint inputList leftSplitList =
     case inputList of
         [] ->
             -- This is a base case, we end here if we ran out of elements
             (List.reverse leftSplitList, [])

         head :: tail ->
              if splitPoint > 0 then
                    -- This is the recursive case
                    -- Note the typical trick here: we are shuffling elements
                    -- from the input list and putting them onto the
                    -- leftSplitList.
                    -- This will reverse the list, so we need to reverse it back
                    -- in the base cases
                    splitHelper (splitPoint - 1) tail (head :: leftSplitList)
               else
                    -- here we got to the split point,
                    -- so the rest of the list is the output
                    (List.reverse leftSplitList, inputList)

Use List.foldl

split : Int -> List a -> (List a, List a)
split i xs =
  let
    f : a -> (List a, List a) -> (List a, List a)
    f x (p, q) =
      if List.length p >= i then
        (p, q++[x])
      else
        (p++[x], q)
  in
    List.foldl f ([], []) xs
  • When list p reaches the desired length, append element x to the second list q.
  • Append element x to list p otherwise.

Normally in Elm, you use List for a sequence of values. Array is used specifically for fast indexing access.

When dealing with lists in functional programming, try to think in terms of map, filter, and fold. They should be all you need.

To return a pair of something (e.g. two lists), use tuple. Elm supports tuples of up to three elements.

Additionally, there is a function splitAt in the List.Extra package that does exactly the same thing, although it is better to roll your own for the purpose of learning.

Related