Home > Software engineering >  How do I split a list on certain conditions in Haskell?
How do I split a list on certain conditions in Haskell?

Time:02-12

As a programming exercise I'm trying to build a function in Haskell where given a list it splits the list whenever an element is repeated. [1,2,3,3,4,5] would split into [[1,2,3],[3,4,5]] for example. My first idea was to split the list into a list of lists with single elements, where [1,2,3,3,4,5] would become [[1],[2],[3],[3],[4],[5]] and then merge lists only when the elements being compared are not equal, but implementing this has been a headache for me as I'm very new to Haskell and recursion has always given me trouble. I think something is wrong with the function I'm using to combine the lists, it will only ever return a list where all the elements that were broken apart are combined, where [1,2,3,3,4,5] becomes [[1],[2],[3],[3],[4],[5]] but my split_help function will transform this into [[1,2,3,3,4,5]] instead of [[1,2,3],[3,4,5]]

I've pasted my incomplete code below, it doesn't work right now but it should give the general idea of what I'm trying to accomplish. Any feedback on general Haskell code etiquette would also be welcome.

split_breaker breaks the list into a list of list and split_help is what I'm trying to use to combine unequal elements.

split_help x y
     | x /= y = x    y
     | otherwise = []

split_breaker :: Eq a => [a] -> [[a]]
split_breaker [] = []
split_breaker [x] = [[x]]
split_breaker (x:xs) = [x]:split_breaker xs

split_at_duplicate :: Eq a => [a] -> [[a]]
split_at_duplicate [x] = [[x]]
split_at_duplicate (x:xs) = foldl1 (split_help) (split_breaker [xs])

CodePudding user response:

Do you want to work it something like this?

splitAtDup [1,2,3,3,3,4,4,5,5,5,5,6]
[[1,2,3],[3],[3,4],[4,5],[5],[5],[5,6]]

Am I right?

Then do it simple:

splitAtDup :: Eq a => [a] -> [[a]]
splitAtDup (x : y : xs) | x == y = [x] : splitAtDup (y : xs)
splitAtDup (x : xs) =
  case splitAtDup xs of
    x' : xs' -> (x : x') : xs'
    _ -> [[x]]
splitAtDup [] = []

CodePudding user response:

How about using foldr:

main = do
  print $ splitAtDup [1,2,3,3,4,5] -- [[1,2,3],[3,4,5]]
  print $ (splitAtDup [] :: [[Int]]) -- [[]]

splitAtDup :: Eq a => [a] -> [[a]]
splitAtDup = foldr f [[]]
  where f x [[]] = [[x]] -- empty accumulator
        f x (ys@(y:_):sublists)
          | x == y    = [x]:ys:sublists
          | otherwise = (x:ys):sublists
  • Related