How to split a list into two in Haskell? [duplicate] - haskell

This question already has answers here:
Simple haskell splitlist
(3 answers)
Closed 6 years ago.
I'm trying to split a list into two so that when the input is
[1,2,3,5,6]
output would be
[1,2,3][5,6]
but I can't seem to figure it out.
The best I can do is [1,3,6][2,5].

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])

Related

List comprehenension in the case of countpositives

I think about the function to count all positives numbers in a list. My idee was
countPositives :: [Int] -> Int
countPositives xs = length [ x | x <- xs, x > 0]
That code work, but I thinking it is possible to write with the filter function or with guards. Is it possilbe and if yes, how can I write it?
Both approaches would be pretty straightforward.
Filter the collection and count it's length:
countPositives' :: [Int] -> Int
countPositives' = length.filter (>0)
With guards:
countPositives'' :: [Int] -> Int
countPositives'' [] = 0
countPositives'' (x:xs) | x > 0 = 1 + countPositives'' xs
| otherwise = countPositives'' xs
As yet another alternative, use a fold:
ghci> lst = [1, 2, 4, 7, -2, -3, 0, 8]
ghci> foldr (\x i -> if x > 0 then i + 1 else i) 0 lst
5

Return a list, which contains a pair of elements, but only if the respective elements' sums are odd

Implement the oddPairs :: [Int] -> [Int] -> [(Int, Int)] function that returns a list of pairs, but only if the parameters' lists' respective elements' sums are odd.
For example:
oddPairs [1,2,3] [2,2,2] == [(1,2),(3,2)]
oddPairs [1,3,5] [2,4,6] == zip [1,3,5] [2,4,6]
oddPairs [1,2,3] [1,2,3] == []
So far, I've tried
oddPairs (x:xs) (y:ys) | (x+y) `mod` 2 == 0 = []
| (x+y) `mod` 2 /= 0 = [(x, y)] ++ oddPairs (xs) (ys)
And on the first example, it returns only [(1,2)], on the second, it returns the correct values but with a Non-exhaustive patterns error.
In case the two items are even, you should not just return an empty list, but continue the recursion until at least one of the lists is exhausted, so:
oddPairs :: Integral a => [a] -> [a] -> [(a, a)]
oddPairs [] _ = []
oddPairs _ [] = []
oddPairs (x:xs) (y:ys)
-- keep searching for new items &downarrow;
| (x+y) `mod` 2 == 0 = oddPairs xs ys
| otherwise = (x, y) : oddPairs xs ys
Another way to look at the problem is that you want only the pairs that have an odd sum. This is a slight difference in emphasis that might lead to the following.
Use the zip function to combine each list into pairs. Then use filter to find the ones with odd sum.
oddPairs :: Integral a => [a] -> [a] -> [(a, a)]
oddPairs f s = filter oddPair (zip f s)
where oddPair (l, r) = not $ even (l + r)
Quite straightforwardly with a list comprehension:
oddPairs :: [Int] -> [Int] -> [(Int, Int)]
oddPairs ms ns = [(m, n) | (m, n) <- zip ms ns, odd (m + n)]
Indeed:
> oddPairs [1, 2, 3] [2, 2, 2] == [(1, 2),(3, 2)]
True
> oddPairs [1, 3, 5] [2, 4, 6] == zip [1, 3, 5] [2, 4, 6]
True
> oddPairs [1, 2, 3] [1, 2, 3] == []
True

How I make result a list of booleans

I have this:
getMask (/= 3) [1, 2, 3, 4, 5]
and result must be this:
[True, True, False, True, True]
i tried something like this
getMask p xs = [x | (x,m) <- enumerate xs, if p x then True else False]
but i get only numbers. I need list of booleans
You can use map :: (a -> b) -> [a] -> [b]:
> map (/= 3) [1, 2, 3, 4, 5]
[True,True,False,True,True]
or a simple list comprehension:
getMask p xs = [p x | x <- xs]

simpel Haskell list sorting/shuffling in a pattern

I'm trying to make an algorithm that takes in a list and reorganizes the list according to the following operation steps.
[1 , 2, 3, 4 , 5, 6, 7 , 8, 9 ]
[1 , 3, 5 , 7, 9 ] ++ [2 , 4, 6, 8 ]
[1 , 3, 5 , 7, 9 ] ++ [2 , 6] ++ [ 4, 8 ]
[1 , 3, 5 , 7, 9 , 2, 6 , 4, 8 ]
This is I have come so far, then I do not know what I should do next. Any help?
ever xs = if xs == [] then [ ] else head xs: ever (drop 1 residue)
Where residue 1 drop = xs
Here is a CPS version:
shuffle [] = []
shuffle xs = shuffle' xs shuffle where
shuffle' (x:y:xs) cont = x : shuffle' xs (cont . (y:))
shuffle' xs cont = xs ++ cont []
I suggest a more combinatorial approach for better readability.
import Data.Either
alternate :: [a -> b] -> [a] -> [b]
alternate fs = zipWith ($) (cycle fs)
shuffle = (\es -> lefts es ++ rights es) . alternate [Left,Right]
alternate rotates the functions applied to a list. In shuffle the constructors for Either get applied alternately. Then we simply cut lefts and rights out of the list and put them together.
This is what I do:
splitAlt :: [a] -> ([a],[a])
splitAlt = foldr (\x (ys, zs) -> (x:zs, ys)) ([],[])
The splitAlt function splits [1,2,3,4,5,6,7,8,9] into ([1,3,5,7,9],[2,4,6,8]).
shuffle :: [a] -> [a]
shuffle [] = []
shuffle xs = let (ys,zs) = splitAlt xs
in ys ++ shuffle zs
That should give you the result that you desire.

Merge sort in haskell goes in infinite loop

Hi everybody I am attempting to reproduce merge sort in haskel, here is my code:
-- merge
merge :: (Ord a) => [a] -> [a] -> [a]
merge [] [] = []
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys)
| x <= y = x:(merge xs (y:ys))
| otherwise = y:(merge (x:xs) ys)
-- split
splitIn2 :: (Ord a) => [a] -> ([a],[a])
splitIn2 [] = ([],[])
splitIn2 xs = splitAt ((length xs `div` 2)+1) xs
-- msort
msort :: (Ord a) => [a] -> [a]
msort [] = []
msort [x] = [x]
msort (xs) = merge (msort as) (msort bs)
where (as,bs) = splitIn2 xs
It compiles on ghc, and it works for:
*Main> msort([])
[]
*Main> msort([1])
[1]
However it doesnt do its job properly because it starts too loop infinitely (at least this is what I thought) and it doesnt print anything.
I think it is because I dont remove elements from the lists like I did in other recursive experiment, any suggestion?
The problem is that when length xs == 2,
(length xs `div` 2) + 1
= (2 `div` 2) + 1
= 1 + 1
= 2
and splitAt 2 xs returns (xs, []). Since the first list is still of length 2,
msort will try to splitIn2 it down again in an infinite loop.
To solve this, you can simply get rid of the +1; it's completely unnecessary. You can
also eliminate the special case for the empty list, since splitAt 0 [] = ([], []).
splitIn2 xs = splitAt (length xs `div` 2) xs
*Main> splitIn2 [1, 2, 3, 0, 5, 6]
([1,2,3,0],[5,6])
And after small change (deleting +1 ):
splitIn2 xs = splitAt ((length xs `div` 2)) xs
It works:
*Main> splitIn2 [1, 2, 3, 0, 5, 6]
([1,2,3],[0,5,6])
*Main> msort [1, 2, 3, 0, 5, 6]
[0,1,2,3,5,6]

Resources