Related
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
So I have a list list of numbers from 3 to 10. I want to get the last number that is bigger than 5 and smaller than 11.
*Main> greatestIndexInRange [3, 6, 7, 2, 5, 1, 0, 10, 2] 5 11
You could reverse the list, filter by your predicate and select the resulting list's head (which would be the last element in the original list) in linear time. Or you could select the last element in the filtered list.
greatestIndexInRange :: Ord a => [a] -> a -> a -> a
greatestIndexInRange xs l h = head . filter (\x -> x > l && x < h) . reverse $ xs
greatestIndexInRange :: Ord a => [a] -> a -> a -> a
greatestIndexInRange xs l h = last $ filter (\x -> x > l && x < h) xs
For example:
greatestIndexInRange [3, 6, 7, 2, 5, 1, 0, 10, 2] 5 11
-- 10
Note that this is a partial function that will fail if no element in the list is in the given range, e.g.:
greatestIndexInRange [1, 2, 3] 5 11
*** Exception: Prelude.head: empty list
As Chris suggested in the comments, you could also use find from Data.List on the reversed list instead of filter+head for a slightly more elegant implementation:
import Data.List (find)
greatestIndexInRange :: Ord a => [a] -> a -> a -> Maybe a
greatestIndexInRange xs l h = find (\x -> x > l && x < h) . reverse $ xs
The function now returns a Maybe. This would also resolve the above issue of it being a partial function:
greatestIndexInRange [3, 6, 7, 2, 5, 1, 0, 10, 2] 5 11
-- Just 10
greatestIndexInRange [1, 2, 3] 5 11
-- Nothing
This will let you do what you want on GHC 9.2 or newer:
{-# LANGUAGE ImpredicativeTypes #-}
import Control.Monad
import Data.Functor.Identity
lastJust :: forall f a b. Foldable f => (a -> Maybe b) -> f a -> Maybe b
lastJust p xs = foldr go id xs Nothing where
go :: a -> (forall t. Applicative t => t b -> t b) -> forall t. Applicative t => t b -> t b
go x acc z = maybe (acc z) (pure . runIdentity . acc . Identity) $ p x
greatestIndexInRange :: (Foldable t, Ord a) => t a -> a -> a -> Maybe a
greatestIndexInRange xs lo hi = lastJust (\x -> x <$ guard (x > lo && x < hi)) xs
You may wish to choose using filter with last than using reverse with find. The better solution depends on factors such as: the location in the list of the element we want, how many elements that match our predicate exist in the list, etc. You might decide on a case-by-case basis, but either solution is fine!
For instance, if the element we want is one and at the beginning, definitely reversing it and using find is worse than using filter with last.
Equally, if we have lots of elements that match our filter's predicate, uniformly distributed across the list, you will be better off reversing the list and use find.
It would be wise to wrap your result in a Maybe in case there is none. The idea is that you need to get to the end of the list somehow. So either way, you will not get a better solution than linear time, unless the list is ordered in which case you could do a binary search.
import Data.List
greatestIndexInRange :: Ord a => [a] -> a -> a -> Maybe a
greatestIndexInRange xs x y = find (\z -> z > x && z < y) (reverse xs)
Output:
*Main Data.List> greatestIndexInRange [3, 6, 7, 2, 5, 1, 0, 10, 2] 5 11
Just 10
*Main Data.List> greatestIndexInRange [1, 2, 3] 5 11
Nothing
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 ↓
| (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
I'm trying to do the following:
The function I'm writing takes list of tuples of ints [(x,y),(i,j)...] in range 0-6
I want to return an [Int] where each element is a count of how many of its
respective number were seen in the list.
e.g. [(0,1), (1,2), (2,3)] would return [1, 2, 2, 1, 0, 0, 0].
in other words, one 0, two 1's, two 2's 1 three and no 4s, 5s or 6s
countNumbers :: [(Int, Int)] -> [Int]
countNumbers [] = [0, 0, 0, 0, 0, 0, 0]
but am not sure how to go about this as I am somewhat new to Haskell.
EDIT - I've found a solution - please let me know if there's a more succinct way to code it !
type ProbabilityMatrix = (Int,Int,Int,Int,Int,Int,Int)
-- converts list of tuples into list of ints as suggested
tupleToList :: [(Int, Int)] -> [Int]
tupleToList ((a,b):xs) = a : b : tupleToList xs
tupleToList _ = []
tupleToList2 :: [Int] -> ProbabilityMatrix -> ProbabilityMatrix
tupleToList2 [] list = list
tupleToList2 (x : xs) (zero, one, two, three, four, five, six)
| x == 0 = tupleToList2 xs (zero + 1, one, two, three, four, five, six)
| x == 1 = tupleToList2 xs (zero, one + 1, two, three, four, five, six)
| x == 2 = tupleToList2 xs (zero, one, two + 1, three, four, five, six)
| x == 3 = tupleToList2 xs (zero, one, two, three + 1, four, five, six)
| x == 4 = tupleToList2 xs (zero, one, two, three, four + 1, five, six)
| x == 5 = tupleToList2 xs (zero, one, two, three, four, five + 1, six)
| x == 6 = tupleToList2 xs (zero, one, two, three, four, five, six + 1)
| otherwise = tupleToList2 xs (zero + 1, one, two, three, four, five, six)
How about you create the result list of Ints for each tuple, and then merge them together with a Sum function. You'd need at least two functions with signatures:
tupleToList :: (Int, Int) -> [Int]
and
sumLists :: [Int] -> [Int] -> [Int]
The first one will detect both items in the tuple, and generate the corresponding list for it, e.g. tupleToList (4, 2) -> [0,0,1,0,1,0,0].
The second function will merge two lists of ints by summing 2 counters at the same index, e.g. sumLists [0,1,1,0,1] [1,1,0,0,0] -> [1,2,1,0,1]. You can do this recursively until you end up with 1 list that will be the answer to the problem.
You'd execute tupleToList for each of the elements in the tuple list (probably with map) and then consolidate the resulting list by executing sumLists for 2 lists iteratively (maybe with foldl)
This approach is rather naive and would probably run slowly for bigger inputs.
You can try this solution:
-- flattens a list of tuples into a list
flatten :: (Num a) => [(a, a)] -> [a]
flatten xs = concat [[a,b] | (a, b) <- xs]
-- updates list element at a position
update_list :: (Num a) => Int -> [a] -> [a]
update_list n xs = take n xs ++ [(xs !! n) + 1] ++ drop (n + 1) xs
-- performs count of numbers
count_numbers :: [(Int, Int)] -> [Int]
count_numbers xs = go (flatten xs) acc
where go [] acc = acc
go (x:xs) acc = go xs (update_list x acc)
acc = replicate 7 0
Where it first flattens a list:
*Main> flatten [(0,1), (1,2), (2,3)]
[0,1,1,2,2,3]
Then updates a list at a certain position:
*Main> update_list 1 (replicate 7 0)
[0,1,0,0,0,0,0]
And performs counting of list elements similarly to your function tupleToList2, where an accumulator of the number counts is stored and updated:
*Main> count_numbers [(0,1), (1,2), (2,3)]
[1,2,2,1,0,0,0]
*Main> count_numbers [(0,1), (1,2), (2,4)]
[1,2,2,0,1,0,0]
*Main> count_numbers [(0,0), (1,0), (3,6)]
[3,1,0,1,0,0,1]
I'm writing a prefix function that will take a binary function and a list of numbers as parameters, and returns a list formed by computing the successive function and accumulating as you go.
To make things simple, Here's an example:
prefix (+) [2, 4, 1, 1]
returns [2, 6, 7, 8]
prefix (+) [0, 2, -3, 4, -5]
returns [0, 2, -1, 3, -2]
prefix max [2, 3, 1, 1]
returns [2, 3, 3, 3]
Here's my code so far however I get an error when i try to load the file because 'list is not in range'. How can i rewrite it so it makes sense to the compiler? Any help will be appreciated.
prefix' :: (a -> b) -> [a] ->[b]
prefix' _ [] = []
prefix' f (x:xs)
| ((list !! x) == 0) = f (list !! 0) (list !! 0)
| otherwise = prefix' f xs
Try this
prefix::(a -> a -> a) -> [a] -> [a]
prefix f lst| null lst = []
| null (tail lst) = lst
| otherwise = h : prefix' f (f h) (tail lst) where
h = head lst
prefix' fn fc (x:xs) | null xs = [acc]
| otherwise = acc : prefix' fn (fn acc) xs where
acc = fc x
I will try to explain the above code as much as possible. The type signature of the function is one that takes a function (a->a->a) and a list [a] as parameter and returns another list with that function applied to each adjacent pair of the list. The a in the parameter list simply implies any type (which can be anything). If we had specified a specific type (i.e. in Title case), the function will only work with that specific type
The function works by first checking if the list it recieved is empty (null lst), if so we simply return an empty list
The next thing it checks for is if the list only contains one item in it (null (tail lst)), in that case, we simply return the list
The third case is when we actually do something, and the first thing we do is to append the first element in the list to head of our new list (head lst) and call another function which we have defined on the fly to do compute the rest of the list (: prefix' f (f (head lst)) (tail lst)). Note the : separates the head from the rest of the list
The prefix' function has a type signature of (a -> a -> a) -> (a -> a) -> [a] -> [a] so as you can see the only thing different about it is that it takes one extra parameter which is a function (fc) that takes an element of type a and returns an element of type a. To create this function, we have simply passed one parameter to the initial function recieved as argument which creates this new function. This will be useful in computing the rest of the list
The base case for this new function is that if the list only contains one element, it applies the new parameter function fc to that element in the list and returns a list containing the return value of the function
Otherwise it will apply fc to the first element of the list and we generate fc again by applying fn to the return value of fc x.
If you are interested in learning how all these work, this is the website I've been using and my knowledge of haskell has improved greatly due to this website, so highly recommended
Isn't what you want to implement the scanl1 function? I'm a beginner too, but from what I understood, it goes like this:
scanl1 :: (a -> a -> a) -> [a] -> [a]
scanl1 f (x:xs) = scanl f x xs
scanl1 _ [] = []
The scanl function. which scanl1 uses, goes like this:
scanl :: (b -> a -> b) -> b -> [a] -> [b]
scanl = scanlGo
where
scanlGo :: (b -> a -> b) -> b -> [a] -> [b]
scanlGo f q ls = q : (case ls of
[] -> []
x:xs -> scanlGo f (f q x) xs)
Here's what hackage has to say about scanl:
scanl :: (b -> a -> b) -> b -> [a] -> [b] Source
scanl is similar to foldl, but returns a list of successive reduced values from the left:
scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
Note that
last (scanl f z xs) == foldl f z xs.
So, I guess the flow of execution goes like this:
scanl1 (+) [2, 4, 1, 1]
scanl (+) 2 [4, 1, 1]
scanlGo (+) 2 [4, 1, 1]
2 : scanlGo (+) (+ 2 4) [1, 1]
2 : 6 : scanlGo (+) (+ 6 1] [1]
2 : 6 : 7 : scanlGo (+) (+ 7 1) []
2 : 6 : 7 : 8 : scanlGo []
2 : 6 : 7 : 8 : []
[2, 6, 7, 8]
The same thing happens with the (*) and the max functions that you mentioned. Hope this helps.