Function on previous result - haskell

I have a function that a should run on a list. First, I have to compare the first two elements in the list with the function, then compare the third element with the result of the first comparison and so on, so that the result is just one element. I feel like I should use iterate, but I couldn't make it work. How can I do this?
combineOption :: Cell -> Cell -> Cell
combineOption 'f' 'f' = 'f'
combineOption 'e' 'e' = 'e'
combineOption _ _ = 'u'
combineRow :: [Cell] -> [Cell] -> [Cell]
combineRow [] [] = []
combineRow l k = [ combineOption (l !! i) (k !! i) | i <- [0..(length(l)-1)] ]
combineLineOptions :: [[Cell]] -> [Cell]
combineLineOptions l = iterate ... <==================
where type Cell = Char

have a function that a should run on a list. First, I have to compare the first two elements in the list with the function, then compare the third element with the result of the first comparison and so on, so that the result is just one element.
IIUC, that is exactly what foldl1 does. E.g., if "comparison" is difference, then
Prelude Data.List> let l = [1, 2, 3]
Prelude Data.List> foldl1 (-) l
-4
"compares" 1 and 2, then "compares" the result with 3, so it is 1 - 2 - 3 = -4.

Related

How many elements are the same in two lists, which have duplicate elements

I try to find the number of elements that are the same in two lists. There are duplicate elements in two lists.
What I want:
-- (because there are two 's' in both lists )
duplicateEle "sssf" "ssah" = 2
-- (because there are two 'a' and one 's' in both lists, intotal 3 common elements)
duplicateEle "aass" "aaas" = 3
-- (because there are two 'a' and two 's' in both lists, intotal 4 common elements)
duplicateEle "ssaa" "ssaa" = 4
My strategy is check each element in List1 to see if it is the element in List2.
if each element of the List1 is the element of the List2.
If true, count 1 and delete (Data.List) the corresponding element in the second list.
For example,
input "dddd" "ssdd" output 2 because there are two d in both lists.
First I check if the 1st element in List1 which is d is an element in List2, the result is True, so I delete only one d in List2, count +1, now count is 1.
Then I check if the 2nd element in List1 which is d is an element in List2, the result is also True, so, I delete one d in List2,count +1, now count is 2.
Because there is not any d left in List2, so, the count will stay at 2.
My code is: (wrong)
import Data.List
duplicateEleCount :: [Char] -> [Char] -> Int
duplicateEleCount (x:xs) ys =
let count = if x `elem` ys then do 1 (delete x ys) else 0
in count + duplicateEleCount xs ys
What you wrote is not so Haskelly. Since it's strings, we can sort them, then group:
import Data.List
-- group :: Eq a => [a] -> [[a]] -- Defined in `Data.List'
dupreps :: String -> String -> Int
dupreps a b = r
where
x = group $ sort a
y = group $ sort b
Now we have them both ordered and grouped, we can just advance along the two lists in an obvious way,
r = merge'n'count x y 0
merge'n'count _ [] cnt = cnt
merge'n'count [] _ cnt = cnt
merge'n'count (g:gs) (f:fs) cnt
| head g == head f
= merge'n'count gs fs (cnt + min (length g) (length f))
| head g < head f
= merge'n'count gs (f:fs) cnt
| head g > head f
= merge'n'count (g:gs) fs cnt
So that we have e.g.
> dupreps "aab" "abbc"
2
> dupreps "aab" "aabbc"
3
> dupreps "aabccc" "bbc"
2
The groups g and f in merge'n'count are always non-empty by construction, so using head is OK.
If you just want to find the number of common elements between two lists which have repeated items, you can simply do this:
f x y = length $ nub $ intersect x y
intersect will find the common elements (with repetition*), and nub will get the distinct values from that list.
Note: intersect will only include repetition from the first argument i.e. intersect "ss" "s" will return "ss" but intersect "s" "ss" will return just "s".
EDIT: Based on the clarification, we can use foldl to get the desired outcome like so:
dup x y = fst $ foldl (\acc z -> if z `elem` (snd acc) then ((1 + fst acc), delete z (snd acc)) else acc) (0,y) x
This applies the strategy outlined in the question - if the element is found in current value of second list, increase the count and modify the second list, else do nothing.
I believe, this is what you intended to write?
import Data.List
duplicateEleCount :: [Char] -> [Char] -> Int
duplicateEleCount (x:xs) ys =
let (count, ys') = if x `elem` ys then (1, delete x ys) else (0, ys)
in count + duplicateEleCount xs ys'
duplicateEleCount [] _ = 0
You can't use do like you were trying to do. Remember that all variables in Haskell are immutable, so delete doesn't change the original list, it returns a new one that we will have to pass along to the recursive call.
A note on performance: this function is O(n*m), since we have to traverse the whole second list for every element in the first list. We can sort the lists first and perform something similar to the merge operation from merge sort to bring it down to O(n*log(n) + m*log(m))).
On another note, because of haskell's laziness, we can split the function up to one like this, without losing any performance and gaining flexibility:
import Data.List
duplicateElems :: [Char] -> [Char] -> [Char]
duplicateElems (x:xs) ys =
if x `elem` ys
then x : duplicateElems xs (delete x ys)
else duplicateElems xs ys
duplicateElems [] _ = []
duplicateEleCount xs ys = length $ duplicateElems xs ys

Haskell don't really know what to name this

I'm trying to make it so that on a tuple input (n,m) and a list of tuples xs , if the first item in the tuple in xs is in (n,m) then keep it that way in the new list otherwise add the a tuple consisting of some value k from n to m as a first element and as second element it should be 0.My question is:how can i say "repeat 0" using guards ? Since clearly my code won't run since my code says "repeat = 0"
expand :: (Int,Int) -> Profile ->Profile
expand (n,m) [] = zip [n..m] (repeat 0)
expand (n,m) (x:xs) = zip [n..m] (repeat (|(fst (x) `elem` [n..m]) == False = 0
|otherwise = snd (x))
You can use a helper function here that converts a number in the [ n .. m ] range to a 2-tuple. Here we thus try to find an element in the list xs that matches with the first item of that tuple, if we do not find such element, we use 0:
import Data.List(find)
expand :: (Int,Int) -> Profile -> Profile
expand (n,m) xs = map go [n .. m]
where go i | Just l <- find (\(f, _) -> f == i) xs = l
| otherwise = (i, 0)
For a list, find was implemented as [src]:
find :: (a -> Bool) -> [a] -> Maybe a
find p = listToMaybe . filter p
filter thus will make a list that contains the elements that satisfy the predicate p, and listToMaybe :: [a] -> Maybe a will convert an empty list [] to Nothing, and for a non-empty list (x:_) it will wrap the first element x in a Just data constructor. Due to Haskell's laziness, it will thus look for the first element that satisfies the predicate.
this thus gives us:
Prelude Data.List> expand (2,7) [(4, 2.3), (6, 3)]
[(2,0.0),(3,0.0),(4,2.3),(5,0.0),(6,3.0),(7,0.0)]

Haskell turning list of tuples into list of lists

I am trying to turn a list of tuples into a list of lists. For example, if I have the list [(9,1), (6,3), (4,1)], then this will turn into [[9, 6, 4],[6],[6]]. What's happening is that in the list of tuples [(a,b)], a represents a number from 0-9 and b represents the occurrence of that number, a will always be unique.
What I am trying to do it go go over the list n times, where n = maximum b in the list of tuples. Each time I go over the list, I take a and put it into a list, then decrement b by 1. If b == 0 then I just skip it.
So from my example, I take [9,6,4] and throw them into a list, then decrement the b of each of them, so now the list would look like [(9,0),(6,2),(4,0)]. Then going over again, I take [6], list of tuples now looks like [(9,0), (6,1), (4,0)]. Finally, take [6] one last time, and now ever b in the list of tuples is 0 so it is done.
I have created a a function that takes the 1st element from the list of tuples iff b is >= 1, but I don't know how I can iterate this over the updated list with all `b - 1' for each tuple.
turnIntList :: [(Integer, Integer)] -> [[Integer]]
turnIntList [] = []
turnIntList x = ([map (\(a, b) -> case (a,b) of _ | b >= 1 -> a | otherwise -> -1) x])
I have also tried creating another helper function that takes a list of tuples and will turn them into a list depending on how large b is. From the main function, I would try to send [(a, 1), (b, 1)...] to create the list, then keep track of decrementing b here until it's done. So, for this function:
pairingL :: [(Integer, Integer)] -> [Integer] -> [Integer]
pairingL ((a,b):xs) l -- = if b /= 0 then [a,b-1] else []
| null xs = if b == 1 then [a] ++ l else if b > 1 then [a] ++ l ++ pairingL [(a,b-1)] l else l
| otherwise =
if b /= 0 then [a] ++ l ++ pairingL ((a,b-1):xs) l else pairingL xs l
pairingL [(9,1), (7,2), (5,1)]
[9,7,7,5]
pairingL [(1,1), (2,1), (3,1)]
[1,2,3]
pairingL [(1,2), (2,2), (3,2)]
[1,1,2,2,3,3]
I've tried looking into unzipping the list and working with that, iteration, and repeat but I can't figure out how to get the function to go over the list multiple times and updating the list with the new b values then going again.
In conclusion, what I am trying to do is something like:
turnIntList [(9,3),(5,1),(2,1)]
[[9,5,2],[9],[9]]
turnIntList [(1,1),(2,1),(3,1),(4,1)]
[[1,2,3,4]]
turnIntList [(1,2),(2,2),(3,2)]
[[1,2,3],[1,2,3]]
turnIntList [(4,2),(6,1)]
[[4,6],[4]]
Process:
I am taking the first element from the tuples, adding them to a list, then subtracting the second element by 1. After doing this for each tuple in the list, I repeat the process until all the second elements for each tuple is 0
Important notes: again, in the list of tuples [(a,b)], a will ALWAYS be UNIQUE number from 0-9, and b >= 0
This maybe
turnIntList :: [(Integer, Integer)] -> [[Integer]]
turnIntList [] = [] -- if it doesn’t compile use [[]]
turnIntList ls = [i | (i, _) <- ls] : turnIntList [(i, n - 1) | (i, n) <- ls, n - 1 > 0]

How to list all different 2-element list in a list in haskell?

For example, I have [1,2,3], I want to get [[1,2],[1,3],[2,3]]. Besides, in the list, [1,2] and [2,1] are assumed as same so just leave one in the result, and I also want to add a condition, like 'sum of the elements in sub-list is smaller than 4', then the result should be [[1,2]].
Any one knows how to solve this?
Use a list comprehension:
input = [1,2,3]
output = [ [x,y] | x <- input, y <- input, x < y, x + y < 4]
-- [[1,2]]
Here is a function which works for different types:
import Math.Combinat.Sets (choose)
select :: Int -> ([a] -> Bool) -> [a] -> [[a]]
select k filtering list = filter filtering (choose k list)
Examples:
>>> select 2 (\x -> sum x < 5) [1,2,3]
[[1,2],[1,3]]
>>> select 2 (not . elem "hello") ["hello", "how", "are", "you"]
[["how","are"],["how","you"],["are","you"]]

How can i count elements of a tuple in Haskell?

So i've got a list of tuples like this one :
xs = [("a","b"),("a","c"),("b","d")
and i want a function that counts the number of times a certain value appears in the first position of the tuple. If i used the list xs and the letter 'a', it would return the value 2, because the letter 'a' appears two times in the first position of the tuple. This function shouldn't be recursive.
So what i've got is this:
f xs = (fst $ unzip xs) / length(xs)
Now i have all the elements down on a list. this would be easy if it was recursive, but if i don't want it that way, how can i do it ?
If we're not using recursion, we need to use some higher order functions. In particular, filter looks helpful, it removes elements who don't satisfy some condition.
Well if we use filter we can get a list of all elements with the first element being the correct thing.
count :: Eq a => [(a, b)] -> Int
count x = length . filter ((== x) . fst)
I suppose since you're studying, you should work to understand some folds, start with
count x = foldr step 0
where step (a, b) r | a == x = 1 + r
| otherwise = r
If you map the first elements into a list find all occurences of your value and count the length of the resulting list:
countOccurences :: Eq a => a -> [(a, b)] -> Int
countOccurences e = length . filter ((==)e) . map fst

Resources