Unexpected issue with max function in Haskell - list

I have this function that removes the maximum value of a list and it seems to work, and when I keep adding numbers it works until I add a new high number. Then it will still remove only the old max number. But when I start a new list it will work again. Can anyone explain what is going on, and what I am doing wrong?
removeMax :: [Int] -> [Int]
removeMax [] = []
removeMax [x] = []
removeMax (x:y:xs)
| x > y = (y:xs)
| otherwise = x : removeMax (y:xs)
And here is the outputs of several tests I made:
*Main> removeMax [1,9,3,2,6]
[1,3,2,6]
*Main> removeMax [1,9,3,2,6,8]
[1,3,2,6,8]
*Main> removeMax [1,9,3,2,6,8,7]
[1,3,2,6,8,7]
*Main> removeMax [1,9,3,2,6,8,7,14]
[1,3,2,6,8,7,14]
*Main> removeMax [1,9,3,2,6,8,7,14]
[1,3,2,6,8,7,14]
*Main> removeMax [1,9,3,2,6,8,7,14]
[1,3,2,6,8,7,14]
*Main> removeMax [1,3,14,5]
[1,3,5]
*Main> removeMax[1,3,8,9]
[1,3,8]
*Main> removeMax [1,2,3,67,87,12]
[1,2,3,67,12]
*Main> removeMax [1,2,3,67,87,12,88]
[1,2,3,67,12,88]
As you can see it works when you keep doing it on new lists and when you use an old list and only add smaller numbers.

There's nothing weird about the way your function behaves - you defined it to remove the first number that is larger than its successor.
To really remove the maximum from a given list, the easiest approach is to:
find the maximum by scanning the whole list
remove it
An implementation of this approach is pretty straightforward using two helper functions:
findMax: [Int] -> Int
removeElement: [Int] -> Int -> [Int]
However, you should also consider edge cases:
what happens if the maximum occurs more than once? I.e. should removeMax [1, 3, 2, 3] return [1,2,3], [1,2] or [1,3,2] ?
does your new implementation handle the empty list correctly? (your current one does)

Related

Concatenating 2 inputted lists in Haskell

I'm trying to combine 2 lists from input but I am getting an error every time.
Here is my code:
myAppend :: [a] -> [a] -> [a]
myAppend a b = zipWith (+) a b
Getting this error:
"No instance for (Num a) arising from a use of ‘+’"
I was given this solution but it doesn't really make sense to me
myAppend :: [a] -> [a] -> [a]
myAppend [] xs = xs
myAppend (y:ys) xs = y:(myAppend ys xs)
I don't really understand the second and third line.
Can anyone help?
Thanks
Your myAppend does not concatenate two lists, it aims to sum elementwise the two lists, so myAppend [1,4,2,5] [1,3,0,2] will produce [2,7,2,7]. It will require a Num a constraint, since it can only work if the elements of the lists are Numbers:
myAppend :: Num a => [a] -> [a] -> [a]
myAppend a b = zipWith (+) a b
As for the solution here it uses recursion. Lists in Haskell are like linked lists: you have a an empty list ("nil") which is represented by the [] data constructor, and a node ("cons") which is represented with (x:xs) where x points to the first item, and xs points to the list of remaining elements. So [1,4,2,5] is short for (1:(4:(2:(5:[])))).
If we want to append [1,4] and [2,5] we thus want to produce a list (1:(4:(2:(5:[])))) out of (1:(4:[])) and (2:(5:[])). This means we create a linked list with all the elements of the first list, but instead of pointing to the empty list [], we let it point to the second list for the remaining elements. We do this through recursion:
myAppend (y:ys) xs = y : myAppend ys xs
will match if the first list unifies with the (y:ys) pattern. In that case we thus produce a list with y as first element, and the result of myAppend ys xs as as list of remaining elements ("tail"). Eventually we will thus call myAppend ys xs with the empty list [] as first item. In that case, we thus return the second list instead of the empty list, to append the second list to it.
We thus make calls that look like:
myAppend [1, 4] [2, 5]
= myAppend (1:(4:[])) (2:(5:[]))
-> 1 : (myAppend (4:[]) (2:(5:[])))
-> 1 : (4 : (myAppend [] (2:(5:[]))))
-> 1 : (4 : (2:(5:[]))
= [1, 4, 2, 5]

following the class correctly but the code is not accepted

I want it to show the desired n final numbers, but the GHCi is giving an error in the code
nLast :: int -> [a] -> [a]
nLast 0 _ = []
nLast _ [] = []
nLast n (x:xs) = nultimos (n-1) xs
You can work with two enumerators over the list. You give one of the enumeraters a head start of n items and each time you let both the enumerators make one hope. If the first runner reaches the empty list, then we know that the second runner has n items they still need to enumerate over.
We thus can implement this with:
nLast :: Int -> [a] -> [a]
nLast n ls = go (drop n ls) ls
where go (_:xs) (_:ys) = …
go [] ys = …
here you still need to fill in the … parts. I leave this as an exercise.
In the above example there is a pattern that we do not cover, a pattern where the first list is a non-empty list (_:_) and the second is empty []. We know that this can never happen, it might still be better however to add a clause for this.

Beginner Haskell | Group List of Ints

I'm trying to make a function that makes a list of list of ints, can you lend a hand?
groupUp :: [Int] -> [[Int]]
example:
groupUp [1,2,2,3,3,3] == [[1],[2,2],[3,3,3]]
The closest I could come was:
groupUp [] = [[]]
groupUp (x:[]) = []
groupUp(x:y:xs)
| x==y = [x,y] : groupUp (xs)
| otherwise = [x] : groupUp (y:xs)
But this limits the list to a group of maximum 2 (pairs) and not more. What should I change?
Edit: this one works, thx for the help!
groupUp xs= helper 0 xs
where helper _ []=[]
helper i xs= takeWhile (==(xs!!i))xs: helper (i) (dropWhile (==(xs!!i))xs)
Instead of laborously comparing single elements, use a function that compares elements until some condition.
Prelude> span (==2) [2,2,3,3,3,4,4,4,4]
([2,2],[3,3,3,4,4,4,4])
Then, recurse, using the remainder of that:
groupUp [] = [[]] -- This should probably just be [], not [[]].
groupUp (x:xs) = case span (==x) xs of
(thisGroup, others) -> (x:thisGroup) : groupUp others
Of course you can also define a version of span yourself if you prefer.

Haskell -- Sums Accumulated in Lists

I need to create or know if there is a function in Haskell that allows you to add items from a list. So, for example:
cumulativeAmount :: [Integer] -> [Integer]
cumulativeAmount [1,2,5,8,8,0,4,2] = [1,3,8,16,24,24,28,30]
cumulativeAmount [1,4,7,0,5] = [1, 1+4, 1+4+7, 1+4+7+0, 1+4+7+0+5] = [1,5,12,12,17]
I tried to use the map and scanl function, but I didn't get what I wanted, because I added all the elements.
This is exactly the purpose of scanl1 :: (a -> a -> a) -> [a] -> [a]:
Prelude> scanl1 (+) [1,2,5,8,8,0,4,2]
[1,3,8,16,24,24,28,30]
scanl1 takes as input a function f :: a -> a -> a (here (+)), and a list of as. It constructs a list where the first item is the first item of the list. This is the first value of the accumulator. Then for every value, the accumulator is updated by calling f with the accumulator and the next value of the list, this item is then yielded.
So in case of scal1 (+) [1,2,5] the first item we emit is 1, we also set the accumulator to 1. The next item is 2, so we call (+) 1 2 (which is 3) and this is the result and the new accumulator, next we call (+) ((+) 1 2) 5 (which is 8), etc.
But I think it is better, as an exercise to use recursion. Like said before we use an accumulator. We can implement this by introducing an extra function where the accumulator is a function we pass through the recursive calls (and update). So in that case it looks like:
cumulativeAmount :: [Integer] -> [Integer]
cumulativeAmount [] = ...
cumulativeAmount (x:xs) = go x xs
where go x xs = ...
so here the first argument of go (x) is the accumulator. I leave it as an exercise to implement it with recursion.
What about using an accumulator:
cumulativeAmount :: (Num a) => [a] -> [a]
cumulativeAmount xs = go xs 0
where go [] acc = []
go (x:xs) acc = (acc+x) : go xs (acc+x)
Which works as follows:
*Main> cumulativeAmount [1,2,5,8,8,0,4,2]
[1,3,8,16,24,24,28,30]
The above code keeps a state variable acc to accumulate sums whenever a new number is encountered, and adds the new sum to the resulting list.
Now a good exercise would be to replace the above code with higher order functions.
Off the top of my head, you could solve this with a list comprehension, like so:
cumulativeAmount xs = [ sum $ take x xs | x <- [1..length xs] ]

How to recursively call a function over the length of the list?

I had an interview question, and it has been bugging me since then.
I have a function, fill, that does the computation like taking two lists and then replacing 2s in the second list, where ever there are 2s in the first list and also once 2s are filled in the second list from the first list, then it can flow till a 1 is encountered. For eg:
Two lists [2,1,2,1,2] [0,0,1,0,0] is passed, so the output I get is [2,2,1,2,2]. Now, I want to write a function that takes an argument something like this: [[2,1,2,1,2],[0,0,1,0,0],[0,0,0,0,0]], I want to apply my above function recursively till the end of this list of lists. So like first [2,1,2,1,2] [0,0,1,0,0] are passed to fill, then it should get the result [2,2,1,2,2], then [2,2,1,2,2] and [0,0,0,0,0] should be passed, getting the result [2,2,2,2,2]. How can I do that?
EDIT:
I did this:
fillAll::[[Int]]->[Int]
fillAll [] = []
fillAll (x:xs) =
(foldl' seep x xs) $
helper2 x
helper2:: [Int] -> Bool
helper2 lst =
if 2 `elem` lst then True else False
So, you have your function fill:
fill :: [Int] -> [Int] -> [Int]
And you want to turn this into a function which takes a list of lists:
fillRec :: [[Int]] -> [Int]
This is a natural case for a fold. This repeatedly 'folds' each element of a list together using a combining function. We need to make sure the list isn't empty:
fillRec [] = []
fillRec (x : xs) = foldl fill x xs
This version of foldl (e.g. folds from the left, rather than from the right) is non-strict, which can cause large memory accumulation. It's better to use the strict variant foldl' from Data.List:
fillRec (x : xs) = foldl' fill x xs
I'm going to assume that you already have fill :: [Int] -> [Int] -> [Int] defined. If so, this problem is pretty easy to solve using a fold. Explicitly, you could do something like
fillAll :: [[Int]] -> [Int]
fillAll [] = []
fillAll (x:xs) = go x xs
where
go first [] = first
go first (second:rest) = go (fill first second) rest
Or you can use one of the built-in folds:
fillAll [] = []
fillAll (x:xs) = foldl fill x xs
but as Impredicative points out, you'll have better performance with foldl' from Data.List