Suggestion on the hackerRank solution about alphabets and weight - haskell

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

Related

How to use show function with 2 values

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

Haskell compare issue

I use recursion to compare two numbers(ex 123 is the same with 123) and store how many digits they have in common(ex 123 compared to 123 has 3 and with 124 has 2).
While my program does find that number i want to put conditions for every situation (ex if they have 2 digits in common output value 44 or if they have 3 do something else etc.) but no comparison is done. Can someone please explain to me what and why that happens. Here my code :
dg :: Int->Int->Int
dg 0 0 = 0
dg x y = if (c==2) then 23 else 24 -- c = common digits
where c = digits (x `div` 10) (y `div` 10) + if (x `mod` 10 == y `mod` 10) then 1 else 0
I run hugs deleting the "if" condition, giving input 10 10 the output is 2 but when i leave it on and rerun it, it goes to 24 (while 23 is correct). I'm really confused.
To find how many digits two Int have in common, using the string representation isn't too bad (It's actually terrible, see update below).
commonDigits :: Int -> Int -> Int
commonDigits a b = length . filter id $ zipWith (==) (reverse $ show a) (reverse $ show b)
reverse is needed to make sure the digits align properly.
If you're into point-free style:
import Data.Function
commonDigits :: Int -> Int -> Int
commonDigits = fmap (length . filter id) . zipWith (==) `on` reverse . show
Then if you want to return a special Int depending on the result of commonDigits you can use a separate function:
specialResult :: Int -> Int -> Int
specialResult a b =
case commonDigits a b of
2 -> 23
3 -> 48
_ -> 256
Update: For negative integers this method is not good. If only one of the argument is negative this function should behave like your mod 10 version. If both are negative there is the possibility that the '-' sign is counted as a digit.
Let's use a digits function that will give a list of digits for both positive and negative numbers from the least significant to the most significant digits. What happens if the number 0 is given as input, should we return an empty list or [0]? Your call on that one, but I'm going to assume you want [0].
digits :: Int -> [Int]
digits 0 = [0]
digits n = digits' (abs n)
where
digits' 0 = []
digits' n = n `mod` 10 : digits' (n `div` 10)
With this new digits function we can rewrite commonDigits to:
commonDigits :: Int -> Int -> Int
commonDigits = fmap (length . filter id) . zipWith (==) `on` digits

Haskell input with txt file

I am working on a program to get the closest prime number by the exponent of 2, this is between an interval.
module Main where
import Data.Char
import System.IO
import Control.Monad (liftM)
data PGetal = G Bool | P Int
instance Show PGetal where
show (P n) = show n
show (G False) = "GEEN PRIEMGETAL GEVONDEN"
mPriem::(Int, Int) -> PGetal
mPriem (x,y) | (x > y) = G False
| (x > 1000000) = G False
| (y > 1000000) = G False
| (null (getAllPriem(x,y))) = G False
| otherwise = P (kleinsteVerschilF(getAllPriem(x,y),1000000,1))
kleinsteVerschilF:: ([Int], Int , Int) -> Int
kleinsteVerschilF ([],_, priemGetal) = priemGetal
kleinsteVerschilF (priem1:priemcss, kleinsteVerschil,priemGetal)=
if(kleinsteVerschil <= kleinsteVerschilMetLijst (priem1,(getMachtenVanTwee(0)),1000000))then kleinsteVerschilF(priemcss, kleinsteVerschil,priemGetal)
else kleinsteVerschilF (priemcss,kleinsteVerschilMetLijst(priem1,(getMachtenVanTwee(0)),1000000), priem1)
kleinsteVerschilMetLijst :: (Int,[Int],Int) -> Int
kleinsteVerschilMetLijst ( _,[],kleinsteVerschil) = kleinsteVerschil
kleinsteVerschilMetLijst (x,tweeMachten1:tweeMachtencss,kleinsteverschil)=
if((abs(x-tweeMachten1)) < kleinsteverschil)
then kleinsteVerschilMetLijst(x,tweeMachtencss, (abs(x-tweeMachten1)))
else kleinsteVerschilMetLijst(x,tweeMachtencss, kleinsteverschil)
getAllPriem :: (Int, Int) ->[Int]
getAllPriem (x,y) = filter isPriem [x..y]
getMachtenVanTwee ::(Int) -> [Int]
getMachtenVanTwee (macht)
|(functieMachtTwee(macht)< 1000000) = (functieMachtTwee(macht)) : (getMachtenVanTwee ((macht+1)))
| otherwise = []
functieMachtTwee:: (Int) -> Int
functieMachtTwee (x) = 2^x
isPriem n = (aantalDelers n)==2
aantalDelers n = telAantalDelersVanaf n 1
telAantalDelersVanaf n kandidaatDeler
| n == kandidaatDeler = 1
| mod n kandidaatDeler == 0
= 1 + telAantalDelersVanaf n (kandidaatDeler+1)
| otherwise
= telAantalDelersVanaf n (kandidaatDeler+1)
aantalDelers2 getal = telDelers getal 1 0
where telDelers n kandidaat teller
| n == kandidaat = 1+teller
| mod n kandidaat == 0
= telDelers n (kandidaat+1) (teller+1)
| otherwise
= telDelers n (kandidaat+1) teller
transform :: [String] -> [PGetal]
transform [] = []
transform (cs:css) =
let (a : b: _ ) = words cs
in (mPriem ((read(a)),(read(b))): transform css)
main :: IO ()
main = do
n <- read `liftM` getLine :: IO Int
lss <- lines `liftM` getContents
let cases = take n lss
let vs = (transform (lss))
putStr $ unlines $ map show vs
When I use the mPriem function, it works fine.
But it needs to work with an input txt file, so I made a .exe file with the ghc command. I also added this .txt file in the folder.
10
1 1
1 3
1 100
200 250
14 16
5 10
20 31
16 50
100 120
5200 7341
When I use in command line this command, it does nothing. There is no output. I can't CTRL+C to stop the program, so I think it crashes. But I don't know what's wrong.
type invoer.txt | programma.exe
Your program works, but is not that efficient and personally I find it not that elegant (sorry :S) because you introduce a lot of "noise". As a result it takes a lot of time before output is written.
If I understand the problem statement correctly, each line (except the first), contains two integers, and you need to count the amount of prime numbers between these two numbers (bounds inclusive?)
First of all, you can do this more elegantly by defining a function: cPrime :: Int -> Int -> Int that takes as input the two numbers and returns the amount of prime numbers:
cPrime :: Int -> Int -> Int
cPrime a b = count $ filter isPrime [a .. b]
You can improve performance by improving your prime checking algorithm. First of all, you do not need to check whether 1 is a divisor, since 1 is always a divisor. Furthermore, you can prove mathematically that there is no divisor greater than sqrt(n) (except for n) that divides n; unless there is another divider that is smaller than sqrt(n). So that means that you can simply enumerate all numbers between 2 and sqrt n and from the moment one of these is a divisor, you can stop: you have proven the number is not prime:
isPrime :: Int -> Bool
isPrime 1 = False
isPrime 2 = True
isPrime n = all ((0 /=) . mod n) (2:[3,5..m])
where m = floor $ sqrt $ fromIntegral n
Now I'm not sure what you aim to do with kleinsteVerschilF.

Haskell reverse Integer with recursion

I want to reverse an Integer in Haskell with recursion. I have a small issue.
Here is the code :
reverseInt :: Integer -> Integer
reverseInt n
| n>0 = (mod n 10)*10 + reverseInt(div n 10)
| otherwise = 0
Example 345
I use as input 345 and I want to output 543
In my program it will do....
reverseInt 345
345>0
mod 345 10 -> 5
reverseInt 34
34
34>0
mod 34 10 -> 4
reverseInt 3
3>0
mod 3 10 -> 3
reverseInt 0
0=0 (ends)
And at the end it returns the sum of them... 5+4+3 = 12.
So I want each time before it sums them, to multiple the sum * 10. So it will go...
5
5*10 + 4
54*10 + 3
543
Here's a relatively simple one:
reverseInt :: Int -> Int
reverseInt 0 = 0
reverseInt n = firstDigit + 10 * (reverseInt $ n - firstDigit * 10^place)
where
n' = fromIntegral n
place = (floor . logBase 10) n'
firstDigit = n `div` 10^place
Basically,
You take the logBase 10 of your input integer, to give you in what place it is (10s, 100s, 1000s...)
Because the previous calculation gives you a floating point number, of which we do not need the decimals, we use the floor function to truncate everything after the decimal.
We determine the first digit of the number by doing n 'div' 10^place. For example, if we had 543, we'd find place to be 2, so firstDigit = 543/100 = 5 (integer division)
We use this value, and add it to 10 * the reverse of the 'rest' of the integer, in this case, 43.
Edit: Perhaps an even more concise and understandable version might be:
reverseInt :: Int -> Int
reverseInt 0 = 0
reverseInt n = mod n 10 * 10^place + reverseInt (div n 10)
where
n' = fromIntegral n
place = (floor . logBase 10) n'
This time, instead of recursing through the first digit, we're recursing through the last one and using place to give it the right number of zeroes.
reverseInt :: Integer -> Integer
reverseInt n = snd $ rev n
where
rev x
| x>0 = let (a,b) = rev(div x 10)
in ((a*10), (mod x 10)*a + b)
| otherwise = (1,0)
Explanation left to reader :)
I don't know convenient way to found how many times you should multiply (mod n 10) on 10 in your 3rd line. I like solution with unfoldr more:
import Data.List
listify = unfoldr (\ x -> case x of
_ | x <= 0 -> Nothing
_ -> Just(mod x 10, div x 10) )
reverse_n n = foldl (\ acc x -> acc*10+x) 0 (listify n)
In listify function we generate list of numbers from integer in reverse order and after that we build result simple folding a list.
Or just convert it to a string, reverse it and convert it back to an integer:
reverseInt :: Integer -> Integer
reverseInt = read . reverse . show
More (not necessarily recursion based) answers for great good!
reverseInt 0 = 0
reverseInt x = foldl (\x y -> 10*x + y) 0 $ numToList x
where
numToList x = if x == 0 then [] else (x `rem` 10) : numToList (x `div` 10)
This is basically the concatenation of two functions : numToList (convert a given integer to a list 123 -> [1,2,3]) and listToNum (do the opposite).
The numToList function works by repeatedly getting the lowest unit of the number (using rem, Haskell's remainder function), and then chops it off (using div, Haskell's integer division function). Once the number is 0, the empty list is returned and the result concatenates into the final list. Keep in mind that this list is in reverse order!
The listToNum function (not seen) is quite a sexy piece of code:
foldl (\x y -> 10*x + y) 0 xs
This starts from the left and moves to the right, multiplying the current value at each step by 10 and then adding the next number to it.
I know the answer has already been given, but it's always nice to see alternative solutions :)
The first function is recursive to convert the integer to a list. It was originally reversing but the re-conversion function reversed easier so I took it out of the first. The functions can be run separately. The first outputs a tuple pair. The second takes a tuple pair. The second is not recursive nor did it need to be.
di 0 ls = (ls,sum ls); di n ls = di nn $ d:ls where (nn,d) = divMod n 10
di 3456789 []
([3,4,5,6,7,8,9],42)
rec (ls,n) = (sum [y*(10^x)|(x,y) <- zip [0..] ls ],n)
Run both as
rec $ di 3456789 []
(9876543,42)

Convert a string representing a binary number to a base 10 string haskell

I have the string "1001" and I want the string "9".
The numeric library has the (rather clunky) showIntAtBase, but I haven't been able to find the opposite.
It's been a while since the original post but, for future readers' benefit, I would use the following:
import Data.Char (digitToInt)
import Data.List (foldl')
toDec :: String -> Int
toDec = foldl' (\acc x -> acc * 2 + digitToInt x) 0
No need to slow things down by using ^, reverse, zipWith, length, etc.
Also, using a strict fold reduces memory requirements.
Here is more or less what you were looking for from Prelude.
From Numeric:
(NB: readInt is the "dual" of showIntAtBase, and readDec is the "dual" of showInt. The inconsistent naming is a historical accident.)
import Data.Char (digitToInt)
import Data.Maybe (listToMaybe)
import Numeric (readInt)
readBin :: Integral a => String -> Maybe a
readBin = fmap fst . listToMaybe . readInt 2 (`elem` "01") digitToInt
-- readBin "1001" == Just 9
From PLEAC:
bin2dec :: String -> Integer
bin2dec = foldr (\c s -> s * 2 + c) 0 . reverse . map c2i
where c2i c = if c == '0' then 0 else 1
This helps? http://pleac.sourceforge.net/pleac_haskell/numbers.html
from the page:
bin2dec :: String -> Integer
bin2dec = foldr (\c s -> s * 2 + c) 0 . reverse . map c2i
where c2i c = if c == '0' then 0 else 1
-- bin2dec "0110110" == 54
Because
1001 = 1 * 2^0 + 0 * 2^1 + 0 * 2^2 + 1 * 2^3 = 1 + 0 + 0 + 8 = 9
┌───┬───┬───┬───┐
│1 │0 │0 │1 │
├───┼───┼───┼───┤
│2^3│2^2│2^1│2^0│
└───┴───┴───┴───┘
so obviously:
fromBinary :: String -> Int
fromBinary str = sum $ zipWith toDec (reverse str) [0 .. length str]
where toDec a b = digitToInt a * (2 ^ b)
binario :: Int -> [Int]
binario 1 = [1]
binario n = binario(div x 2)++(mod n 2:[])
credits to #laionzera
import Control.Monad
import Data.Bits (shift)
-- Dirty version
binToInt :: String -> Int
binToInt = foldl' step 0
where
step acc '1' = shift acc 1 + 1
step acc _ = shift acc 1
-- Maybe version
mayBinToInt :: String -> Maybe Int
mayBinToInt = foldM step 0
where
step acc '0' = pure $ shift acc 1
step acc '1' = pure $ shift acc 1 + 1
step acc _ = Nothing
(Of course you might want to return Nothing on empty string in the second one as well.)

Resources