. Archive of katas that I have solved
Somebody solved with JUST ONE recursion! Amazing! Check this variant
Learned that you can traverse lists like this
allCombinations xs = [(x,y) | x <- xs, y <- xs]
-- allCombinations [1,2,3]
-- [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
Also you can use zip [0..] to get indexes!!!
tryOutZip list = [(fst x, fst y, snd x + snd y) | x <- zipped, y <- zipped]
where
zipped = zip [0..] list
-- tryOutZip [1,2,3]
-- [(0,0,2),(0,1,3),(0,2,4),(1,0,3),(1,1,4),(1,2,5),(2,0,4),(2,1,5),(2,2,6)]
Then you can restrict by index, and build only needed combinations
tryOutZip list = [(fst x, fst y, snd x + snd y) | x <- zipped, y <- zipped, fst x < fst y]
where
zipped = zip [0..] list
-- tryOutZip [1,2,3]
-- [(0,1,3),(0,2,4),(1,2,5)]
Somebody solved by just using Binary xor
import Data.Bits (xor)
findOdd :: [Int] -> Int
findOdd = foldr xor 0
for example if we take [5,6,6]
- 0
xor
5 = 5 - 5
xor
6 = 3 - 3
xor
6 = 5
for [2,1,3,2,3]
- 0
xor
2 = 2 - 2
xor
1 = 3 - 3
xor
3 = 0 - 0
xor
2 = 2 - 2
xor
3 = 1
My First 5ku Kata in Haskell!!!
Used Data.List.Split For a first time
chunksOf
was very helpfull for this task ))
Haskell is getting kind of anoying with no brackets, and discoragment of variables...
moveChar :: Int -> (Int -> Int) -> Char -> Char
moveChar
charStartsAt
modifyNumber
characterToMove = chr (
(
(
modifyNumber (
ord characterToMove
) - charStartsAt
) `mod` lettersCount
) + charStartsAt
)
Tried to add some variables. This feels more comfortable, but is this FP way?
lettersCount :: Int
lettersCount = ord 'z' - ord 'a' + 1
moveChar :: Int -> (Int -> Int) -> Char -> Char
moveChar
charStartsAt
modifyNumber
characterToMove = chr resultingIndex
where
resultingIndex = resultingIndexFrom0 + charStartsAt
resultingIndexFrom0 = mod (modifyNumber charIndexFrom0) lettersCount
charIndexFrom0 = charIndex - charStartsAt
charIndex = ord characterToMove
shift :: Int -> Char -> Char
shift i c | isLower c = chr . (+97) . flip mod 26 . (+) (i - 97) $ ord c
| isUpper c = chr . (+65) . flip mod 26 . (+) (i - 65) $ ord c
| otherwise = c
This looks like FP!
chr . (+97)
instead doing it in layers, we compose!flip mod 26
more composition! Nice tricks!
lettersCount :: Int
lettersCount = ord 'z' - ord 'a' + 1
moveChar :: Int -> (Int -> Int) -> Char -> Char
moveChar
charStartsAt
modifyNumber = chr . (+ charStartsAt) . flip mod lettersCount . modifyNumber . flip (-) charStartsAt . ord
Now it's FP
We need one more change to be 100% FP
make all variable names unreadable, and move some calculations to magic numbers!
moveChar :: Int -> (Int -> Int) -> Char -> Char
moveChar x y = chr . (+ x) . flip mod 26 . y . flip (-) x . ord
Good luck finding out what it does, in a months :D
Another function in that solution is also interesting It uses this trick
zipWith shift [n..] xs
So if we have function
shift :: Int -> Int -> Int
shift x y = x * 100 + y
And we want to apply this shift
function to each element of an array of numbers like map but x
should be index of an element, and y an element value
We can simply do that
zipWith shift [1..] $ [5,7,9]
-- [105,207,309]
Moreover if we don't know starting index we can use a variable
zipWith shift [n, n+1..] $ [5,7,9]
In this particular kata, that would help us get rid of passing Int -> Int -> Int
function to tell how we should change index
And remove [(Int, Char)]
type from our function
When I was finished with kata, I still had one error where I have to return
["ab", "bc", "sm", "gg", ""]
I was returning only 4 elements
["ab", "bc", "sm", "gg"]
So I fixed this by taking 5 elements and adding one empty at the end
take 5 $ encodeAndBrake s i ++ [""]
But this could have beed written if FP way using composition, like that!
take 5 . (++ [""]) $ encodeAndBrake s i
To get amount of items in a chunk I had to implement this function
getDivider :: String -> Int
getDivider x = ceiling ( fromIntegral (length x) / 5 ) :: Int
-- ceiling ( fromIntegral (17) / 5 )
It takes list [Char]
And checking how many items should be in a piles to get 5 chunks at most!
For example
If length is 17
the five parts will have lengths of 4, 4, 4, 4, 1
So this function would return 4
that will sufice chunksOf
method and split list accordingly
But this could have been done more simply by using quotRem
17 `quotRem` 5
quotRem - basically 2 functions called on same arguments and result put in a pair
(quot x y, rem x y)
quot 17 5
== 3
rem 17 5
== 2
So we get (3,2)
We increment sft x + 1
and we are golden
Was harder than I have expected...
data DateHMS = DateHMS Int Int Int deriving (Show)
It's quite eazy to work with those, to extract values you can simmply do that in arguments by diconstruction
fromDateHMStoSecnds :: DateHMS -> Int
fromDateHMStoSecnds (DateHMS h m s) = convertToMiliseconds h m s
Creating an instance DateHMS 0 0 0
convertStringToHMS i
| length spl == 3 = DateHMS (readInt 0) (readInt 1) (readInt 2)
| otherwise = DateHMS 0 0 0
I wrote this f to convert from HH:mm:ss to milliseconds, it works but kind of ugly
convertToMiliseconds :: Int -> Int -> Int -> Int
convertToMiliseconds h m s = s * 1000 + m * 60 * 1000 + h * 60 * 60 * 1000
I found this function in best solutions section
timeToSec :: String -> Int
timeToSec = sum . zipWith (*) [3600,60,1] . map read . splitOn "|"
It kind of does to many things as for me, but zipWith
trick cood be used in my function
convertToMiliseconds :: Int -> Int -> Int -> Int
convertToMiliseconds h m s = sum . zipWith (*) [1000, 1000*60, 1000*60*60] $ [s, m, h]
And as ussual it's not 100% FP if we don't have magic numbers
and unreadable function/variable names
convToMs :: Int -> Int -> Int -> Int
convToMs x y z = sum . zipWith (*) [1000, 60000, 3600000] $ [z, y, x]
Now we golden :D
To construct part of report string I have used this helper
fromDateHMSToReport :: String -> DateHMS -> String
fromDateHMSToReport prefix (DateHMS h m s) = prefix ++ withLeadingZero h ++ "|" ++ withLeadingZero m ++ "|" ++ withLeadingZero s
And used it to make final string
getRangeStats :: [Char] -> String
getRangeStats = getStats "Range: " range
getAverageStats :: [Char] -> String
getAverageStats = getStats " Average: " average
getMedianStats :: [Char] -> String
getMedianStats = getStats " Median: " median
-- And then doing this
concat [getRangeStats x, getAverageStats x, getMedianStats x]
Let's make it look better with help of printf
We start with a helper, we remove prefix, and use printf
fromDateHMSToReport :: DateHMS -> String
fromDateHMSToReport (DateHMS h m s) =
printf "%s|%s|%s" (withLeadingZero h) (withLeadingZero m) (withLeadingZero s)
And as ussual make variable/functionNames unreadable to reach 100% FP
frDtToRep :: DateHMS -> String
frDtToRep (DateHMS h m s) =
printf "%s|%s|%s" (wthLd0 h) (wthLd0 m) (wthLd0 s)
And instead of concat we now have
getResult :: String -> String
getResult x = printf "Range: %s Average: %s Median: %s" r a m
where
r = getStats range x
a = getStats average x
m = getStats median x
To get HH:mm:ss back I wrote this function
fromSecondsToDateHMS :: Int -> DateHMS
fromSecondsToDateHMS seconds = DateHMS h m s
where
(h,mLeft) = quotRem seconds (60*60 * 1000)
(m,ms) = quotRem mLeft (60 * 1000)
(s, _) = quotRem ms 1000
In one of the solutions I saw somebody using divMod
So what the difference?
quotRem
- simultaneous quot
and rem
quotRem 157 50 = (3,7)
quotRem (-157) 50 = (-3, -7)
quotRem (-157) (-50) = (3,-7)
divMod
- simultaneous div
and mod
divMod 157 50 = (3,7)
divMod (-157) 50 = (-4,43)
divMod (-157) (-50) = (3, -7)
Where
quot
- integer division truncated toward zero
quot 86 10 = 8
div
- integer division truncated toward negative infinity
div 86 10 = 8
The difference comes with negative numbers
div (-86) 10 = -9
- truncated toward negative infinityquot (-86) 10 = -8
- truncated toward zero
rem
- integer remainder
rem 86 10 = 6
mod (-1700) 1000 = -700
mod
- integer modulus
mod 86 10 = 6
mod (-1700) 1000 = 300
So in this particular case, as we don't work with negative numbers, it doesn't matter
Eazy kata should be 7 or 8 ku
Used zipWith that I have learned before ))
checkNumb :: Int -> Bool
checkNumb x = t == x
where t = sum . (flip . zipWith) (^) [1..] . map digitToInt $ show x
You can use (== n)
as a function in composition, instead of using variable
f n = (== n) . sum . zipWith (flip (^)) [1..] . map digitToInt . show $ n
Instead of
filter (\i -> length i == sz)
We can use composition
filter ((== n) . length)
It seems like understanding the description is more chalanging than actually solving the kata
Quite convinietly instead of doing
map fromJust . filter isJust . map isIt $ [n..m]
you can use mapMaybe
That will filter out Notings and map your List
mapMaybe isIt [n..m]
An eazy one, straight forward solution
An eazy one, straight forward solution
Someone solved it like this, :D
songDecoder :: String -> String
songDecoder = unwords . words . go
where go [] = []
go ('W':'U':'B':xs) = ' ' : go xs
go (x:xs) = x : go xs
-- And like this
unDub :: String -> String
unDub "" = ""
unDub ('W':'U':'B':s) = ' ': unDub s
unDub (c:s) = c: unDub s
songDecoder :: String -> String
songDecoder = unwords . words . unDub