Sorting a list of lists in Haskell - haskell

I want to write a function that takes a list of sorted lists, then merges everything together and sorts them again.
I managed to write this so far:
merge_:: Ord a => [[a]] -> [a] --takes in the list and merges it
merge_ [] = []
merge_ (x:xs) = x ++ merge_ xs
isort:: Ord a => [a] -> [a] --Sorts a list
isort [] = []
isort (a:x) = ins a (isort x)
where
ins a [] = [a]
ins a (b:y) | a<= b = a:(b:y)
| otherwise = b: (ins a y)
I haven't been able to find a way to combine these two in one function in a way that makes sense. Note that I'm not allowed to use things such as ('.', '$'..etc) (homework)

We start simple. How do we merge two sorted lists?
mergeTwo :: Ord a => [a] -> [a] -> [a]
mergeTwo [] ys = ys
mergeTwo xs [] = xs
mergeTwo (x:xs) (y:ys)
| x <= y = x : mergeTwo xs (y:ys)
| otherwise = y : mergeTwo (x:xs) ys
How do we merge multiple? Well, we start with the first and the second and merge them together. Then we merge the new one and the third together:
mergeAll :: Ord a => [[a]] -> [a]
mergeAll (x:y:xs) = mergeAll ((mergeTwo x y) : xs)
mergeAll [x] = x
mergeAll _ = []
Allright. Now, to sort all elements, we need to create a list from every element, and then merge them back. Let's write a function that creates a list for a single item:
toList :: a -> [a]
toList x = -- exercise
And now a function to wrap all elements in lists:
allToList :: [a] -> [[a]]
allToList = -- exercise
And now we're done. We simply need to use allToList and then mergeAll:
isort :: Ord a => [a] -> [a]
isort xs = mergeAll (allToList xs)
Note that this exercise got a lot easier since we've split it into four functions.
Exercises (which might not be possible for you(r homework))
Write toList and allToList.
Try a list comprehension for allToList. Try a higher order function for allToList.
Write isort point-free (with (.)).
Check whether there is already a toList function with the same type. Use that one.
Rewrite mergeAll using foldr

Try this (not tested):
merge :: Ord a => [a] -> [a] -> [a]
merge [] l1 = l1
merge l1 [] = l1
merge (e1:l1) (e2:l2)
| e1<e2 = e1:merge l1 (e2:l2)
| otherwise = e2:merge (e1:l1) l2

Related

Prevent repeat printing of common list variables Haskell

Currently, I am making a function that can take the values in two lists, compare them, and print any similar values. If a value is duplicated in both lists, it is not printed a second time.
EXAMPLE
INPUT: commons [1,2,2,3,4] [2,3,4,5,2,6,8]
EXPECTED OUTPUT: [2,3,4]
What I currently have causes a repeated values in both lists to repeat in the output. So, in the above example, the 2 would print twice.
Here is the current code I am working on:
commons :: Eq a => [a] -> [a] -> [a]
commons [] [] = []
commons x y = commons_Helper x y
commons_Helper :: Eq a => [a] -> [a] -> [a]
commons_Helper [] [] = []
commons_Helper x [] = []
commons_Helper [] y = []
commons_Helper (x:xs) y =
if elem x y then x : commons_Helper xs y
else commons_Helper xs y
Any and all help would be greatly appreciated.
EDIT: This must remain as commons :: Eq a => [a] -> [a] -> [a], and I cannot import and libraries
You could make your traversal of the xs list a stateful one, the state keeping track of elements that have been already seen. The state begins life as an empty list.
It is possible to do that by adding a 3rd parameter to your helper function, which currently is not very useful.
commons_Helper :: Eq a => [a] -> [a] -> [a] -> [a]
commons_Helper [] ys st = []
commons_Helper (x:xs) ys st =
if (elem x ys && (not $ elem x st)) -- extra test here
then x : (commons_Helper xs ys (x:st))
else commons_Helper xs ys st
commons :: Eq a => [a] -> [a] -> [a]
commons xs ys = commons_Helper xs ys []
This state-based technique is very common in Haskell. There is even a library function: mapAccumL :: (s -> a -> (s, b)) -> s -> [a] -> (s, [b]) to support it.

Merge Tuples that are nested in List of Lists [Haskell]

I'm trying to merge:
[[('a',False),('b',False)]]
with
[[('a',True)],[('b',True)]]
and get the following:
[[(a,True),(b,True),(a,False),('b',False)]]
Essiently merging the two lists tuples into one.
I tried to create a function to do this but I'm not getting the output I want. Here's my current function and the output it gives me
mergeFunc :: [[a]] -> [[a]] -> [[a]]
mergeFunc xs [] = xs
mergeFunc [] ys = ys
mergeFunc (x:xs) ys = x : mergeFunc ys xs
[[('a',True),('b',True)],[('a',False)],[('b',False)]]
It seems that I'm merging a level higher than I want to, but I'm not sure how to fix this.
You can concatenate the sublists together in one list with concat :: Foldable f => f [a] -> [a]:
mergeFunc :: [[a]] -> [[a]] -> [[a]]
mergeFunc xs ys = [concat xs ++ concat ys]
and this will produce:
ghci> mergeFunc [[('a',True)],[('b',True)]] [[('a',False),('b',False)]]
[[('a',True),('b',True),('a',False),('b',False)]]
But then it makes not much sense to wrap the list in a singleton list. In that case it makes more sense to define this as:
mergeFunc :: [[a]] -> [[a]] -> [a]
mergeFunc xs ys = concat xs ++ concat ys
since this removes an unnecessary list level.

Insertion sort using tail recursion & first order function

I'd like to design an algorithm in Haskell using tail recursion and first order programming for insertion sort
I've came up with this solution
isort :: Ord a => [a] -> [a]
isort [] = []
isort [x] = [x]
isort ( x:xs ) = insert ( isort xs )
where insert [] = [x]
insert ( y:ys )
| x < y = x : y : ys
| otherwise = y : insert ys
But I'm not sure if it uses first order and tail recursion.
Can someone come up with an alternative solution using
tail recursion
first order programming
Thanks,
This is the simple version, not using tail recursion nor HOF
sort :: Ord a => [a] -> [a]
sort [] = []
sort [x] = [x]
sort (x:xs) = insert x (sort xs)
insert :: Ord a => a -> [a] -> [a]
insert x [] = [x]
insert x (y:ys) | x < y = x:y:ys
| otherwise = y:insert x ys
You can add an accumulator, that allows us to rewrite the sort using tail recursion:
sort' :: Ord a => [a] -> [a]
sort' xs = sortAcc xs []
sortAcc :: Ord a => [a] -> [a] -> [a]
sortAcc [] acc = acc
sortAcc (x:xs) acc = sortAcc xs (insert x acc)
insert is pretty nicely defined the way it is; but just for the purpose
of using higher order functions, we can define it like:
insert' :: Ord a => a -> [a] -> [a]
insert' x xs = menores ++ x:mayores
where (menores,mayores) = span (<x) xs
where the section (<x) is a function of type Ord a => a -> Bool passed to span.

Haskell Merge Sort

This is an implementation of Mergesort using higher order functions,guards,where and recursion.
However getting an error from compiler 6:26: parse error on input ‘=’
mergeSort :: ([a] -> [a] -> [a]) -> [a] -> [a]
mergeSort merge xs
| length xs < 2 = xs
| otherwise = merge (mergeSort merge first) (mergeSort merge second)
where first = take half xs
second = drop half xs
half = (length xs) `div` 2
I can't see whats wrong? or rather I don't understand the compiler.
Halving a list is not an O(1) operation but O(n), so the given solutions introduce additional costs compared to the imperative version of merge sort. One way to avoid halving is to simply start merging directly by making singletons and then merging every two consecutive lists:
sort :: (Ord a) => [a] -> [a]
sort = mergeAll . map (:[])
where
mergeAll [] = []
mergeAll [t] = t
mergeAll xs = mergeAll (mergePairs xs)
mergePairs (x:y:xs) = merge x y:mergePairs xs
mergePairs xs = xs
where merge is already given by others.
Another msort implementation in Haskell;
merge :: Ord a => [a] -> [a] -> [a]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) | x < y = x:merge xs (y:ys)
| otherwise = y:merge (x:xs) ys
halve :: [a] -> ([a],[a])
halve xs = (take lhx xs, drop lhx xs)
where lhx = length xs `div` 2
msort :: Ord a => [a] -> [a]
msort [] = []
msort [x] = [x]
msort xs = merge (msort left) (msort right)
where (left,right) = halve xs
Haskell is an indentation sensitive programming language, you simply need to fix that (btw. if you are using tabs change that to using spaces).
mergeSort :: ([a] -> [a] -> [a]) -> [a] -> [a]
mergeSort merge xs
| length xs < 2 = xs
| otherwise = merge (mergeSort merge first) (mergeSort merge second)
where first = take half xs
second = drop half xs
half = length xs `div` 2
None of these solutions is as smart as Haskell's own solution, which runs on the idea that in the worst case scenario's these proposed algorithms is still run Theta (n log n) even if the list to be sorted is already trivially sorted.
Haskell's solution is to merge lists of strictly decreasing (and increasing values). The simplified code looks like:
mergesort :: Ord a => [a] -> [a]
mergesort xs = unwrap (until single (pairWith merge) (runs xs))
runs :: Ord a => [a] -> [[a]]
runs = foldr op []
where op x [] = [[x]]
op x ((y:xs):xss) | x <= y = (x:y:xs):xss
| otherwise = [x]:(y:xs):xss`
This will run Theta(n)
Haskell's version is smarter still because it will do an up run and a down run.
As usual I am in awe with the cleverness of Haskell!

How to extract the same elements from two lists in Haskell?

here's my question:
How to extract the same elements from two equal length lists to another list?
For example: given two lists [2,4,6,3,2,1,3,5] and [7,3,3,2,8,8,9,1] the answer should be [1,2,3,3]. Note that the order is immaterial. I'm actually using the length of the return list.
I tried this:
sameElem as bs = length (nub (intersect as bs))
but the problem is nub removes all the duplications. The result of using my function to the former example is 3 the length of [1,3,2] instead of 4 the length of [1,3,3,2]. Is there a solution? Thank you.
Since the position seems to be irrelevant, you can simply sort the lists beforehand and then traverse both lists:
import Data.List (sort)
intersectSorted :: Ord a => [a] -> [a] -> [a]
intersectSorted (x:xs) (y:ys)
| x == y = x : intersectSorted xs ys
| x < y = intersectSorted xs (y:ys)
| x > y = intersectSorted (x:xs) ys
intersectSorted _ _ = []
intersect :: Ord a => [a] -> [a] -> [a]
intersect xs ys = intersectSorted (sort xs) (sort ys)
Note that it's also possible to achieve this with a Map:
import Data.Map.Strict (fromListWith, assocs, intersectionWith, Map)
type Counter a = Map a Int
toCounter :: Ord a => [a] -> Counter a
toCounter = fromListWith (+) . flip zip (repeat 1)
intersectCounter :: Ord a => Counter a -> Counter a -> Counter a
intersectCounter = intersectionWith min
toList :: Counter a -> [a]
toList = concatMap (\(k,c) -> replicate c k) . assocs
intersect :: Ord a => [a] -> [a] -> [a]
intersect xs ys = toList $ intersectCounter (toCounter xs) (toCounter ys)
You could write a function for this. There is probably a more elegant version of this involving lambda's or folds, but this does work for your example:
import Data.List
same (x:xs) ys = if x `elem` ys
then x:same xs (delete x ys)
else same xs ys
same [] _ = []
same _ [] = []
The delete x ys in the then-clause is important, without that delete command items from the first list that occur at least once will be counted every time they're encountered.
Note that the output is not sorted, since you were only interested in the length of the resulting list.
import Data.List (delete)
mutuals :: Eq a => [a] -> [a] -> [a]
mutuals [] _ = []
mutuals (x : xs) ys | x `elem` ys = x : mutuals xs (delete x ys)
| otherwise = mutuals xs ys
gives
mutuals [2,4,6,3,2,1,3,5] [7,3,3,2,8,8,9,1] == [2,3,1,3]

Resources