How to use show function with 2 values - haskell

I am trying to solve the problem on HackerRank https://www.hackerrank.com/challenges/breaking-best-and-worst-records/problem
What the question ask is to display 2 values no of times the record is broken for min score and highest score
I have wrote the algorithm to find it. I am stuck with how to output 2 values.
Following is my solution. Currently it display's the number of highest record broken. I want to show 2 values so that it passes the test in hackerrank.
mxscore::(a,a,a,a) -> a
mxscore (_,a,_,_) = a
mnscore::(a,a,a,a) -> a
mnscore (a,_,_,_) = a
lscore :: (a, a,a,a) -> a
lscore (_,_,a,_) = a
hscore :: (a, a,a,a) -> a
hscore (_,_,_,a) = a
main = interact $ show . hscore .solve . map read . tail . words
solve::[Int] -> (Int, Int, Int, Int)
solve (x:xs) = solve1 x xs
where solve1 d dx = foldl(\acc x -> if x > mxscore acc
then (mnscore acc, x, lscore acc, hscore acc + 1)
else if x < mnscore acc then (x, mxscore acc, lscore acc + 1, hscore acc) else acc ) (d,d,0,0) dx
Current solution works as follows
*Main> solve [10, 5, 20, 20, 4, 5, 2, 25, 1]
(1,25,4,2)
where 4 is number of time lowest record is broken
and 2 is number of time highest record is broken
*Main> solve [3, 4, 21, 36, 10, 28, 35, 5, 24, 42]
(3,42,0,4)
where 0 is number of time lowest record is broken
and 4 is number of times highest record is broken
The first number is no. of scores
The second line is Score
Input:
9
10 5 20 20 4 5 2 25 1
Output :
2 4
Ans. explanation 2 is the number of time the records were broken for highest score
4 is the number of time the records were broken of lowest score

I found the solution to the question. I created 1 more function that would override the show
mxscore::(a,a,a,a) -> a
mxscore (_,a,_,_) = a
mnscore::(a,a,a,a) -> a
mnscore (a,_,_,_) = a
lscore :: (a, a,a,a) -> a
lscore (_,_,a,_) = a
hscore :: (a, a,a,a) -> a
hscore (_,_,_,a) = a
main = interact $ show1 .solve . map read . tail . words
show1::(Int, Int, Int, Int) -> String
show1 (_,_,a,b) = show b ++ " " ++ show a
solve::[Int] -> (Int, Int, Int, Int)
solve (x:xs) = solve1 x xs
where solve1 d dx = foldl(\acc x -> if x > mxscore acc
then (mnscore acc, x, lscore acc, hscore acc + 1)
else if x < mnscore acc then (x, mxscore acc, lscore acc + 1, hscore acc) else acc ) (d,d,0,0) dx
Thanks

Related

recursion apparently has non exhaustive patterns in it

My function rtnDryPlaces is supposed to return a list of all dry places if they were dry on a particular day - with day 1 being yesterday (last element) and day 7 being last week (first element).
type Name = String
type Location = (Float,Float)
type RainfallFigures = [Int]
type Place = (Name,Location,RainfallFigures)
testData=[("London", (51.5, -0.1), [0, 0, 5, 8, 8, 0, 0]),("Cardiff", (51.5 , -3.2),[12, 8, 15, 0, 0, 0, 2])]
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces ((a,(b,c),d):xs) n
| d == [] = []
| (reverse d)!!n-1 == 0 = a:rtnDryPlaces xs n
demo 4 = print (rtnDryPlaces testData 2 )
The second guard reverses the list and returns the element at that index (index is day). If it returns 0, then the name a is appended to the list of names which have also returned 0 for that day. When the test data runs out, so does the rainfall data so I've set the stop condition to be when d = []
One of the problems is that the recursive calls will eventually reach the empty list, and you did not define a result for that:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces [] _ = []
rtnDryPlaces ((a,(b,c),d):xs) n
| d == [] = []
| (reverse d)!!n-1 == 0 = a:rtnDryPlaces xs n
But even then it will not work (yet). For example (reversed d)!!n-1 is interpreted as ((reverse d)!!n)-1, so it first takes the element at index n, and then it will subtract that element with 1. It will not take the n-1 element.
Furthermore if the (reversed d)!!(n-1) is not zero, then that guard will not "fire", and thus we get again an exhaustive pattern failure. We thus should add an otherwise at the end:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces [] _ = []
rtnDryPlaces ((a,_,d):xs) n
| d == [] = []
| (reverse d)!!(n-1) == 0 = a:rtnDryPlaces xs n
| otherwise = rtnDryPlaces xs n
Now this will give us a result:
Prelude> rtnDryPlaces testData 2
["London","Cardiff"]
But we can still make this more elegant by making use of filter and map:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces ps n = map (\(x,_,_) -> x) (filter p ps)
where p (_,_,d) | (0:_) <- drop (n-1) (reverse d) = True
| otherwise = False
or as #DanielWagner says, with list comprehension:
rtnDryPlaces :: [Place] -> Int -> [Name]
rtnDryPlaces ps n = [p | (p, _, d) <- ps, 0 <- take 1 . drop (n-1) . reverse $ d]
Here the take 1 . drop (n-1) will make a singleton list (given the list has enough elements) with the amount of rain for that day. If that then pattern matches with 0, we will yield p in the result. If the value for that day does not match with 0, or the list has not enough elements (then take 1 . drop (n-1) (reverse d) will yield an empty list), then that element is not emitted in the result.

Suggestion on the hackerRank solution about alphabets and weight

I have solved the designer pdf question with haskell. The code works. I am posting the code here to know how I could have done it better.
First line contains the weight of each alphabet
Second line contains the word.
Sample input
1 3 1 3 1 4 1 3 2 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 7
zaba
Output
28
explanation each character would take 1 space and multiply it with the max weight
4 characters * 1 space * 7 weight = 28
'z' has the max weight of 7.
Code
import Data.List
import Data.Maybe
getintval::(Maybe Int) -> Int
getintval Nothing = 1
getintval (Just x) = x
solve'::[Char]->[(Char, Int)] -> Int
solve' ch lst = k $ map getintval $ map (\x -> finder' x) ch
where
k::[Int] -> Int
k fb = (*) (length ch) $ foldl (\acc x -> max acc x) 1 fb
finder'::Char -> Maybe Int
finder' g = case i of
Just(x1,x2) -> Just x2
Nothing -> Just 1
where i = find(\(val1, val2) -> val1 == g) lst
solve::[Char] -> [Char] -> Int
solve wght val = solve' val rec
where
rec::[(Char, Int)]
rec = zipWith (\x y -> (x, y)) ['a'..'z'] word1
word1::[Int]
word1 = map(read::String->Int) $ words wght
main::IO()
main = do
weight <- getLine
pdfstr <- getLine
putStr . show $ solve weight pdfstr
All the test on HackerRank are success

How to change a value in a certain postion of the matrix(and return the whole matrix changed)?

My current code is below. I think all of the functions, except for the last one are correct. What I'm trying to achieve with changeValueMatrix is to give a matrix, a matrix position and a value and then that value will replace the one that is at the current position. I've managed to reach the position and to change the value but I can only return the row on which I changed it and not the whole matrix. I am a Haskell beginner and I've only learned recursion just now but it would be ideal to use it here if possible.
type Matrix a = [[a]]
type MatrixDimension = (Int,Int)
type MatrixPosition = (Int,Int)
matrixDimension :: Matrix a -> MatrixDimension
matrixDimension m = (length m, length (head m))
returnValueList :: Int -> [a] -> a
returnValueList 0 (x:xs) = x
returnValueList i(x:xs) = returnValue (i-1)(xs)
changeValueList :: Int -> a -> [a] -> [a]
changeValueList 0 value (x:xs) = (value:xs)
changeValueList i value (x:xs) = x:(changeValueList (i-1) (value) (xs))
returnValueMatrix :: MatrixPosition-> Matrix a -> a
returnValueMatrix(m,n) matrix = returnValueList n (returnreturnValueList matrix)
changeValueMatrix :: MatrixPosition -> a -> Matrix a -> Matrix a
changeValueMatrix(0,c) value (x:xs) = a:xs
where a = changeValueList c value x
changeValueMatrix(r,c) valor (x:xs) =
where
row = returnValueList r (x:xs)
b = changeValueList c value row
You can build changeValueMatrix from the functions you’ve already defined:
changeValueMatrix :: MatrixPosition -> a -> Matrix a -> Matrix a
changeValueMatrix (r, c) value matrix
= changeValueList r -- (3)
(changeValueList c value -- (2)
(returnValueList r matrix)) -- (1)
matrix
At (1) you look up the row at index r in matrix, at (2) you replace the element at column c in that row with value, and at (3) you replace the row at index r in matrix with the modified row. For example:
-- Given: mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
changeValueMatrix (1, 1) 0 mat
==
changeValueList 1
(changeValueList 1 0
(returnValueList 1 mat))
mat
==
changeValueList 1
(changeValueList 1 0 [4, 5, 6])
mat
==
changeValueList 1 [4, 0, 6] mat
==
[ [1, 2, 3]
, [4, 0, 6]
, [7, 8, 9]
]
If you want a version of this using explicit recursion, which only traverses the rows once, you can inline the definition of changeValueList into changeValueMatrix:
changeValueMatrix (0, c) value (x : xs)
= changeValueList c value x : xs
changeValueMatrix (r, c) value (x : xs)
= x : changeValueMatrix (r - 1, c) value xs
Be aware that your code has a few failure cases, though:
Negative indices will produce infinite loops because you only test for 0 and recur with i - 1 on any other number
Overly large indices will run into the end of the list and crash because you don’t handle the [] case—the pattern matches are non-exhaustive, which the compiler will point out when enabling all warnings with -Wall
Similarly, matrices of zero width or height are representable, but these functions don’t handle the possibility (e.g. matrixDimension calls head on a possibly-empty list); you can avoid this using Data.List.NonEmpty or Data.Array as your backing type, the latter of which is also more efficient

Is it possible to store a removed value in haskell

Hi I am new to haskell and I was just wondering whether it was possible to store a value that has already been removed:
This is my code
input :: Integer -> String
input x = checklength $ intolist x
intolist 0 = []
intolist x = intolist (x `div` 10) ++ [x `mod` 10]
checklength x = if length(x) >= 13 && length(x) <= 16 then doubleall
(init(x)) else "Not valid length of credit card number"
doubleall x = finalcheck $ final $ double (reverse (x))
double x = case x of
[] -> []
[x] -> if (x*2 < 10) then [x*2] else [x*2 `div` 10 + x*2 `mod` 10]
x:y:xs -> (if (x*2 < 10) then [x*2] else [x*2 `div` 10 + x*2 `mod` 10]) ++
y:double xs
final x = (sum x) * 9
finalcheck x = if (x `mod` 10 == ...... ) then "True" else "False"
My code basically takes an input as an integer such as 987564736264535. then makes this integer into a list of number such as [9,8,7..5]. Then it checks the length has to between 13 to 16 digits. If not you get an error statement. If the digits are between the required amount it will go into the doubeall function and remove the last number using (init). the number removed is 5 in which it will double the numbers and reverse the list order. It will then sum the numbers together and multiple by 9. The final step that I have done part of is taking the last digit of the number that has already been summed together and multiplied by 9. So lets give and example lets say I get 456 then I use mod 10 to take the last number which is 6. **Now here is where I am having a problem in which I want to check whether this 6 is equal to the same number that was removed originally in the checklength function when I used init. So in the checklength function I removed the number 5 **
Thanks
Once you remove data, you can't access it again. You need a function that preserves the final checkdigit that you're stripping off.
Since order is (mostly) irrelevant, consider:
validate :: Integer -> Bool
validate x = let digits = toDigits x
in if checkLength digits
then doesMatch . splitCheckdigit $ digits
else False
where
toDigits 0 = [0]
toDigits x = go x
where
go 0 = []
go x = let (d, m) = x `divMod` 10
in m : toDigits d
-- reverses order
checkLength x = let l = length x
in 13 <= l && l <= 16
splitCheckdigit (checkdigit:rest) = (checkdigit, rest)
-- remember we reversed in toDigits, so the *first* digit is the checkdigit!
doesMatch (checkdigit, rest) = let total = (*9) . sum . reduce $ rest
shouldBe = total `mod` 10
in checkdigit == shouldBe
where
reduce (x:y:xs) = (sum . toDigits $ x) : y : reduce xs
reduce [x] = [sum . toDigits $ x]
reduce [] = []
-- note how #toDigits# is reused here rather than redefined.
If you prefer Arrows, validate can be written as:
toDigits >>> ((doesMatch <<< splitCheckdigit) &&& checkLength) >>> uncurry (&&)

Converting list of base 3 digits to corresponding numerical value in Haskell

Below I have defined a function that converts a list of base-3 digits to the corresponding numerical value. For example:
f "201" = (2 * 3^2) + (0 * 3^1) + (1 * 3^0) = 19
f "12" = 5
f "1202" = 47
f "120221" = 430
Here is a definition using comprehension:
f :: String -> Int
f str = sum (listToFinal (stringToTuples str))
Helper functions:
-- 1) converts "201" to "102"
reverse "str"
-- 2) converts "102" to 102
stringToInt :: String -> Int
stringToInt str = read str :: Int
-- 3) converts 102 to ['1','0','2']
intToList :: Int -> [Int]
intToList 0 = []
intToList x = intToList (x `div` 10) ++ [x `mod` 10]
-- 4) converts "201" to [(1,0),(0,1),(2,2)] using reverse, stringToInt, intToList
stringToTuples :: String -> [(Int,Int)]
stringToTuples str = zip (intToList (stringToInt (reverse str))) [0..]
-- 5) converts [(1,0),(0,1),(2,2)] to [1*3^0, 0*3^1, 2*3^2]
listToFinal :: [(Int,Int)] -> [Int]
listToFinal list = [ x * (3^y) | (x,y) <- list ]
Now I'd like to do it with recursion only (well, using basic & library functions too, of course).
An idea: I was thinking of taking the head of each element in the list and simply multiplying it with 3^(length of string - 1). The only problem is, with each recursive call the power of three would have to decrease by 1, e.g. given:
recursive_version "201" = (2 * 3^2) + (0 * 3^1) + (1 * 3^0)
How to implement this?
Here is a much simpler approach; note that, through the use of foldl, it's only "implicitly" recursive, though. For information, digitToInt is exported by Data.Char.
import Data.Char
import Data.List ( foldl' )
--- horner x xs : the value of polynomial 'xs' at point 'x'
horner :: Int -> [Int] -> Int
horner x = foldl' (\c1 c0 -> c1 * x + c0) 0
-- f s : the integer whose representation in base 3 is string 's'
f :: String -> Int
f = horner 3 . map digitToInt
When you define it recursively, the natural way to decrement the length is trimming the array from the head. For example:
base3 x = base3' x 0 where
base3' (d:ds) v = base3' ds $ v + d * 3 ^ length ds
base3' [] v = v

Resources