I am a beginner. So, please correct me if this is wrong or sub-optimal.
internalSplit :: [a] -> Int -> [a] -> [[a]]
split :: [a] -> [[a]]
internalSplit (first:rest) count firstPart
| count == 0 = [firstPart, (first:rest)]
| otherwise = internalSplit rest (count - 1) (firstPart ++ [first])
split myList =
let listLength = length myList
in
if listLength `mod` 2 == 0 then
internalSplit myList (listLength `div` 2) []
else
internalSplit myList ((listLength `div` 2) + 1) []
main = do
print $ split [1, 2, 3, 5, 6]
print $ split [1, 2, 3, 4, 5, 6]
Output
[[1,2,3],[5,6]]
[[1,2,3],[4,5,6]]
Edit:
Managed to use builtin functions and came up with this
internalSplit :: [a] -> Int -> [[a]]
split :: [a] -> [[a]]
internalSplit myList splitLength = [(take splitLength myList), (drop splitLength myList)]
split myList =
let listLength = length myList
in
if listLength `mod` 2 == 0 then
internalSplit myList (listLength `div` 2)
else
internalSplit myList ((listLength `div` 2) + 1)
main = do
print $ split [1, 2, 3, 5, 6]
print $ split [1, 2, 3, 4, 5, 6]
Output
[[1,2,3],[5,6]]
[[1,2,3],[4,5,6]]
Edit 1:
internalSplit :: [a] -> Int -> ([a], [a])
split :: [a] -> ([a], [a])
internalSplit myList splitLength = splitAt splitLength myList
split myList =
let listLength = length myList
in
if listLength `mod` 2 == 0 then
internalSplit myList (listLength `div` 2)
else
internalSplit myList ((listLength `div` 2) + 1)
main = do
print $ split [1, 2, 3, 5, 6]
print $ split [1, 2, 3, 4, 5, 6]
Output
([1,2,3],[5,6])
([1,2,3],[4,5,6])
Edit2
As suggested by Bogdon in the comments section, this can be greatly simplified to this
split :: [a] -> ([a], [a])
split myList = splitAt (((length myList) + 1) `div` 2) myList
main = do
print $ split [1, 2, 3, 5, 6]
print $ split [1, 2, 3, 4, 5, 6]
Output
([1,2,3],[5,6])
([1,2,3],[4,5,6])
Answer from thefourtheye on Stack OverflowSplit a list in with liquidhaskell
Split list into groups of n in Haskell - Code Review Stack Exchange
[Haskell] Recursion in a List Split Function
Splitting a list into two parts
So I'm trying to split a list in half, biasing towards more than half if the list has an odd number of elements.
I want to simply say drop (floor ((length lst) / 2)) mylist but what I've encountered is a messy labyrinth of type casting because haskell apparently needs to have 100 different types of number and none of them are compatible.
now my code looks more like secondHalf lst = drop (toInteger (floor ((fromIntegral (length lst)) / 2))) (lst) but even that doesn't work because drop takes an Int and toInteger returns an Integer
I feel like I've gone in completely the wrong direction, what am I supposed to do?
There are Data.List.Split.chunksOf and Data.List.Grouping.splitEvery implementations of this routine in specialized packages (and a number included in other application packages: search by Int -> [a] -> [[a]] signature on Hayoo).
I think splitEvery implementation is pretty elegant:
splitEvery :: Int -> [a] -> [[a]]
splitEvery _ [] = []
splitEvery n xs = as : splitEvery n bs
where (as,bs) = splitAt n xs
The ready made function chunksOf works very well. When tasked to create 3 elements in sublists with 11 elements in the source list, two elements will be in the last sublist of the result. The following function also includes trailers.
mklsts n = takeWhile (not.null) . map (take n) . iterate (drop n)
I use this as pairs with a 2 for n and no n parameter. Pairs rock.
Edit/Add 4/12/2018
The match up of iterate and splitOn is one made in hell. In the questioner above, placing splitOn in a lambda may have compounded the problems. It is possible to make splitOn work with iterate but you have to ditch the fst of the tuple produced. That defeats the entire purpose. It is way cleaner and easier to use drop n with iterate. The results are the same. That's what the preceding function does. Otherwise, it's the same idea.
Here is a novel way of producing the identical results using tails imported from Data.List in a list comprehension. It picks up stragglers, too.
ts n ls = [take n l|l<-init$tails ls,odd (head l)]
The parameters are size-of-sublist and list
Edit 4/17/2018
Well, since I had some time at work a list comprehension version that does not use tails, a recursive version and a map version.
ttx s ls=[take s.drop x$ls|x<-[0,s..s*1000]]
Recursive
tkn n []=[];tkn n xs=[take n xs]++(tkn n $ drop n xs)
Map
tp n ls=takeWhile(not.null)$ map(take n.flip drop ls) [0,n..]
The list comprehension is virtually infinite. Change [0,s..s*200] to [0,s..] for true infinity. The recursive is, of course, inherently infinite and the map function uses a big takeWhile (not.null) to end itself.
I recently started learning Haskell and programming in general and have been doing a little bit of recursion. I have a pretty fair grasp of it but some functions still have me stumped. For instance, there's this function to split a list into two but I'm not completely sure how it works:
splitList [] = ([],[]) splitList [x] = ([x],[]) splitList (x:y:xys) = (x:xs, y:ys) where (xs, ys) = splitList xys
I would be extremely grateful if someone could provide me step-by-step guide on how this function works. I understand all of the pattern matching, it's just the last line that confuses me.
First of all, note that the function you are trying to construct is already in the standard library, in the Prelude - it is called splitAt. Now, directly looking at its definition is confusing, as there are two algorithms, one which doesn't use the standard recursive structure at all -splitAt n xs = (take n xs, drop n xs) - and one that is hand-optimized making it ugly. The former makes more intuitive sense, as you are simply taking a prefix and a suffix and putting them in a pair. However, the latter teaches more, and has this overall structure:
splitAt :: Int -> [a] -> ([a], [a])
splitAt 0 xs = ([], xs)
splitAt _ [] = ([], [])
splitAt n (x:xs) = (x:xs', xs'')
where
(xs', xs'') = splitAt (n - 1) xs
The basic idea is that if a list is made up of a head and a tail (it is of the form x:xs), then the list going from index k+1 onwards will be the same as the list going from k onwards once you remove the first element - drop (k + 1) (x : xs) == drop k xs. To construct the prefix, you similarly remove the first element, take a smaller prefix, and stick the element back on - take (k + 1) (x : xs) == x : take k xs.
What about this:
splitAt' = \n -> \xs -> (take n xs, drop n xs)
Some tests:
> splitAt' 3 [1..10]
> ([1,2,3],[4,5,6,7,8,9,10])
> splitAt' 0 [1..10]
> ([],[1,2,3,4,5,6,7,8,9,10])
> splitAt' 3 []
> ([],[])
> splitAt' 11 [1..10]
> ([1,2,3,4,5,6,7,8,9,10],[])
> splitAt' 2 "haskell"
> ("ha","skell")
Here's a maximally lazy approach:
splitWhen :: (a -> a -> Bool) -> [a] -> [[a]]
splitWhen f = foldr go [[]] where
go x acc = (x:xs):xss where
xs:xss = case acc of
(z:_):_ | f x z -> []:acc
_ -> acc
splitAtDup :: Eq a => [a] -> [[a]]
splitAtDup = splitWhen (==)
To verify the laziness, try this:
take 2 $ take 4 <$> splitAtDup (1:2:3:3:4:5:6:undefined)
It can be fully evaluated to normal form as [[1,2,3],[3,4,5,6]].
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 [] = []
In a real program you should probably use
splitlist :: [a] -> ([a], [a])
splitlist xs = splitAt ((length xs + 1) `div` 2) xs
(i.e. something along the lines of dreamcrash's answer.)
But if, for learning purposes, you're looking for an explicitly recursive solution, study this:
splitlist :: [a] -> ([a], [a])
splitlist xs = f xs xs where
f (y : ys) (_ : _ : zs) =
let (as, bs) = f ys zs
in (y : as, bs)
f (y : ys) (_ : []) = (y : [], ys)
f ys [] = ([], ys)
You can do it using take and drop:
splitlist :: [a] -> ([a],[a])
splitlist [] = ([],[])
splitlist l = let half = (length(l) +1)`div` 2
in (take half l, drop half l)
or you can take advantage of the function splitAt:
splitlist list = splitAt ((length (list) + 1) `div` 2) list