Home > Enterprise >  How to split a list int groups under certain conditions?
How to split a list int groups under certain conditions?

Time:11-02

I want to split a list into groups with n elements. For example:

n = 2
[1, 2, 3, 4, 5, 6] ->[[1, 2], [3, 4], [5,6]]

n = 3
[1, 2, 3, 4, 5, 6] -> [[1, 2, 3] [4, 5, 6]]

I tried to implement a function, which returns n if n is 0 or greater than the length of the list and the fitted list if n is less than the length of the list.

split :: Int -> [a] -> Either Int [[a]]
split n [a]
   |n <= lenght [a] = Right n (take n [a]) : (split n (drop n [a]))
   |n == 0 = Left n
   |otherwise = Left n

However, I get a "variable not in scope" error. I've already tried around, but I'm stuck. Did I make a mistake with the data types?

CodePudding user response:

You have a typo with lenght vs. length, but if we change that there are still errors.

If we look at Right n (take n [a]) we can see that Right and Left only accept a single argument.

Your pattern split n [a] also only matches a list with a single element.

Let's break this down into smaller pieces. Creating a function that splits a list is straightforward.

split' n [] = []
split' n lst = take n lst : (split' n $ drop n lst)
Prelude> split' 3 [1,2,3,4,5,6]
[[1,2,3],[4,5,6]]

Now it's straightforward to make this local to split to incorporate the checks you specified and return the desired Either type.

split :: Int -> [a] -> Either Int [[a]]
split n [] = Left n
split n lst 
  | n == 0 || n > length lst = Left n
  | otherwise = Right lst'
      where 
        split' n [] = []
        split' n lst = take n lst : (split' n $ drop n lst)
        lst' = split' n lst
  • Related