Haskell turning list of tuples into list of lists - haskell

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]

Related

Haskell - Checking if a list contains an element atleast N times

I am writing a function that checks if a list containts an element at least N times
atLeastNtimes :: Eq a => Int -> a -> [a] -> Bool
atLeastNtimes n a l = n <= (sum [1 | x <- l, (x == a)])
It is working fine with finite list, but I am struggling to make this work for infinite lists, for example:
atLeastNtimes 100 'a' (repeat 'a')
Here are a few possible alternative approaches:
Define your function recursively, without ever trying to inspect the full list but only the needed prefix.
Start by filtering the list so to keep only the elements you want to count. Then, use drop (n-1) xs to drop n-1 elements (if any), and check if the resulting list is not empty (use null). Note that dropping more elements than those in the list is not an error, and it will result in an empty list.
We can separate the problem into two parts. The first just checks whether a list is long enough.
-- | Check whether the length of a list
-- is at least a certain value.
lengthAtLeast :: Int -> [a] -> Bool
lengthAtLeast n0 xs0 = foldr go stop xs0 n0
where
stop n = n <= 0
go _ _ n | n <= 0 = True
go _ r n = r (n - 1)
The second is filtering, which filter does for you. So
atLeastNtimes :: Eq a => Int -> a -> [a] -> Bool
atLeastNtimes n a = lengthAtLeast n . filter (a ==)

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

Double elements in a list if values are over certain threshold

Trying to double elements of a list that are greater than 5 for example.
to double every element in a list i would do this
doubleAll n = [2*x| x <-n]
now i want to double all elements in list that are greater than 5 using list comprehensions.
So if i do this
doubleAll n = [2*x| x <-n, x>5]
My list [1,2,3,4,5] would result in to [10]. But i want my list to show [1,2,3,4,10]
Can anyone explain what i did wrong and how can this be fixed?
An interpretation of [2*x| x <-n, x>5] is:
Take the next element from n and call it x
Proceed if x>5, otherwise go to step 1
Return the value 2*x as the next element of the list.
Repeat
From this it is clear that the x>5 filters out elements of n. The expression is equivalent to:
map (\x -> 2*x) ( filter (\x -> x>5) n )
As Arthur mentioned, you want something like:
[ if x > 5 then 2*x else x | x <- n ]
It's interpretation is:
Take the next value of n and call it x
Return the value if x > 5 then 2*x else x as then next value of the list.
This is clearer to understand if you don't use list comprehensions and use the map and filter operations instead:
-- Apply a function to every element of the list.
map :: (a -> b) -> [a] -> [b]
-- Throw out list elements that don't pass the test.
filter :: (a -> Bool) -> [a] -> [a]
Your original doubleAll is equivalent this:
-- Multiply every element of the list by two.
doubleAll xs = map (*2) xs
The version where you double only if x > 5 would be this:
-- Apply the `step` function to every element of the list. This step function
-- multiplies by two if x >= 5, otherwise it just returns its argument.
doubleAll xs = map step xs
where step x | x >= 5 = 2*x
| otherwise = x
The problem with the list comprehension version that you wrote is that it's instead equivalent to this:
-- Filter out list elements that are smaller than 5, then double the remaining ones.
doubleAll xs = map (*2) (filter (>=5) xs)
The list comprehension solution that produces the result you want would instead be this:
doubleAll xs = [if x >= 5 then x*2 else x | x <- xs]
As a more general remark, I always recommend to newcomers to stay away from list comprehensions and learn the higher-order list functions, which are more general and less magical.

Haskell: recursion with array arguments

Disclaimer: I'm new to Haskell and I don't remember a lot about FP from university, so there may be more than one or two errors in my code. This is also my code for Euler Problem 3.
I'm trying to recursively call a function with two arrays as arguments and an array as a result.
The goal:
assume n is 10 for this question
create a list of all natural numbers from 1 to n (variable is 'allNumbers' is code)
create another list of all natural numbers from 1 to n (variable is 'allFactors' is code)
take the first element in 'allFactors' and multiply the rest of the numbers of 'allFactors' by this number. (this generates an array of numbers)
remove all these numbers from 'allNumbers'
continue from 1 to n until 'allFactors' is empty.
Here is my code:
mkList :: Int -> [Int]
mkList n = [1..n-1]
modArray :: Int -> Int -> [Int]
modArray a b = [ x*b | x <- [1..a], x `mod` b == 0]
modArrayAll :: [Int] -> [Int] -> [Int]
modArrayAll [] [] = []
modArrayAll (x:xs) (y:ys) = (e)
where
m = head( ys)
n = length( xs)
e = (modArrayAll xs ys ) \\ modArray n m
(in main)
let allNumbers = mkList (first + 1)
let allFactors = mkList (first + 1)
let mainList2 = modArrayAll allNumbers allFactors
This results in a null list. However, if I have:
e = xs \\ modArray n m --WORKS for one iteration
I get all the odd numbers from 1 to 10.
My Question: Why isn't this working the way I would expect it? I would expect that the recursive stack would hit the empty array condition and just return an empty array which would not be removed from the calling array and it would continue on returning just the prime numbers?
I copied your goal notes:
-- assume n is 10 for this question
n=10
-- create a list of all natural numbers from 1 to n (variable is 'allNumbers' is code)
allNumbers = [1..n]
-- create another list of all natural numbers from 1 to n (variable is 'allFactors' is code)
allFactors = [2..n] -- i suspect you really wanted this rather than [1..n]
-- take the first element in 'allFactors' and
-- multiply the rest of the numbers of 'allFactors' by this number.
-- (this generates an array of numbers)
-- continue from 1 to n until 'allFactors' is empty
factorProducts = [ x*y | x <- allFactors, y <- allFactors]
-- remove all these numbers from 'allNumbers'
whatYouWanted = allNumbers \\ factorProducts
At the moment you seem to still be thinking in a fairly imperative mindset. Try thinking more about what you want, not how to get it :)
modArray n m creates a list of multiples of m, which you then remove from the "main list" of integers. But modArray n m includes 1*m, so each number is removed because it is a "multiple" of itself. In your test case you get only the odd numbers as a result, while you would want 2 to still be in the resulting list. Additionally 1 is included in your list of factors, which will eliminate all numbers, since they are all multiples of 1.
The terminating case of the recursion is modArrayAll [] [] = [], so there an empty list is returned. Then in the surrounding recursive calls this return value is used here:
(modArrayAll xs ys) \\ modArray n m
This tries to remove further elements (those returned by modArray n m) from the already empty list returned by modArrayAll xs ys. No new elements are added anywhere and the result list stays empty. With your algorithm you want the []-case to return the whole list of numbers, not an empty one. Then the \\ modArray n m in the surrounding recursive function calls can filter out more and more of the non-prime factors.

Resources