[Haskell-beginners] Better Code

Graham Gill math.simplex at gmail.com
Fri Jan 13 23:43:19 UTC 2017


Here's one that does what you want, doesn't require the list to be 
sorted, and groups together consecutive and equal terms:

groupConsecutive :: (Enum a,Eq a) => [a] -> [[a]]
groupConsecutive = foldr go []
     where go x ls@(hd@(y:_):yss)
             | x == y || x == pred y = (x:hd):yss
             | otherwise             = [x]:ls
           go x [] = [[x]]
           go x ([]:yss) = [x]:yss

Then
 > groupConsecutive [1,2,3,7,8,10,11,12]
[[1,2,3],[7,8],[10,11,12]]

 > groupConsecutive [1,2,2,3,2,3]
[[1,2,2,3],[2,3]]

and
 > groupConsecutive "bookkeeper understudy"
["b","oo","kk","ee","p","e","r"," ","u","n","de","rstu","d","y"]

The third case of go will never be reached. If you use a type that is 
also an instance of Bounded, and if your list contains the minimum 
element of the type, you'll get a runtime error on the use of pred. For 
example:

 > groupConsecutive [True,False,True]
*** Exception: Prelude.Enum.Bool.pred: bad argument

Graham

On 13-Jan-2017 11:05 AM, Saqib Shamsi wrote:
> Hi,
>
> The problem that I wish to solve is to divide a (sored) list of 
> integers into sublists such that each sublist contains numbers in 
> consecutive sequence.
>
> For example,
> *Input:* [1,2,3,7,8,10,11,12]
> *Output:* [[1,2,3],[7,8],[10,11,12]]
>
> I have written the following code and it does the trick.
>
> -- Take a list and divide it at first point of non-consecutive number 
> encounter
> divide :: [Int] -> [Int] -> ([Int], [Int])
> divide first [] = (first, [])
> divide first second = if (last first) /= firstSecond - 1 then (first, 
> second)
>                       else divide (first ++ [firstSecond]) (tail second)
>                       where firstSecond = head second
>
>
> -- Helper for breaking a list of numbers into consecutive sublists
> breakIntoConsecsHelper :: [Int] -> [[Int]] -> [[Int]]
> breakIntoConsecsHelper [] [[]] = [[]]
> breakIntoConsecsHelper lst ans = if two == [] then ans ++ [one]
>                                  else ans ++ [one] ++ 
> breakIntoConsecsHelper two []
>                                  where
>                                       firstElem = head lst
>                                       remaining = tail lst
>                                       (one, two) = divide [firstElem] 
> remaining
>
>
> -- Break the list into sublists of consective numbers
> breakIntoConsecs :: [Int] -> [[Int]]
> breakIntoConsecs lst = breakIntoConsecsHelper lst [[]]
>
> -- Take the tail of the result given by the function above to get the 
> required list of lists.
>
> However, I was wondering if there was a better way of doing this. Any 
> help would be highly appreciated.
>
> Thank you.
> Best Regards,
> Saqib Shamsi
>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/beginners/attachments/20170113/a85d590f/attachment-0001.html>


More information about the Beginners mailing list