Skip to content

Instantly share code, notes, and snippets.

@pete-murphy
Last active December 3, 2018 02:36
Show Gist options
  • Save pete-murphy/55e068dc8dbba04f5d1229e7fcc0518f to your computer and use it in GitHub Desktop.
Save pete-murphy/55e068dc8dbba04f5d1229e7fcc0518f to your computer and use it in GitHub Desktop.
Interview Coding Challenge

Example usage

Compile and run with

$ ./main input.txt
Alex: 42 miles @ 34 mph
Dan: 39 miles @ 47 mph
Bob: 0 miles
Driver Dan
Driver Alex
Driver Bob
Trip Dan 07:15 07:45 17.3
Trip Dan 06:12 06:32 21.8
Trip Alex 12:01 13:16 42.0
module Main where
import Data.List
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (listToMaybe, maybe)
import Data.Ord (comparing)
import System.Environment (getArgs)
data ReportEntry = ReportEntry
{ name :: String
, miles :: Int
, mph :: Maybe Int
}
type Report = [ReportEntry]
data CommandEntry
= DriverEntry String
| TripEntry { driverName :: String
, start :: String
, end :: String
, tripMiles :: String }
type CommandEntryMap = Map String (Int, Float)
parseLine :: [String] -> CommandEntry
parseLine ("Driver":name:_) = DriverEntry name
parseLine ("Trip":name:start:end:miles:_) = TripEntry name start end miles
parse :: String -> [CommandEntry]
parse file = parseLine . words <$> lines file
generateReport :: [CommandEntry] -> Report
generateReport =
(reverse . sortBy (comparing name)) <$>
((map . toRepEntry . getTrips) <*> getNames)
formatRepEntry :: ReportEntry -> String
formatRepEntry (ReportEntry name miles mph) =
name ++
": " ++
show miles ++ " miles" ++ maybe "" ((" @ " ++) . (++ " mph") . show) mph
toRepEntry :: CommandEntryMap -> String -> ReportEntry
toRepEntry trips name = toRepEntry' $ Map.lookup name trips
where
toRepEntry' :: Maybe (Int, Float) -> ReportEntry
toRepEntry' (Just (minutes, miles)) =
ReportEntry
name
(round miles)
(Just $ round $ miles / (fromIntegral minutes / 60))
toRepEntry' Nothing = ReportEntry name 0 Nothing
getNames :: [CommandEntry] -> [String]
getNames [] = []
getNames (DriverEntry name:xs) = name : getNames xs
getNames (_:xs) = getNames xs
getTrips :: [CommandEntry] -> CommandEntryMap
getTrips [] = Map.empty
getTrips ((TripEntry name start end miles):xs) =
Map.insertWith
(\(t, m) (t', m') -> (t + t', m + m'))
name
(differenceInMinutes start end, (read miles :: Float))
(getTrips xs)
getTrips (_:xs) = getTrips xs
differenceInMinutes :: String -> String -> Int
differenceInMinutes start end = toMinutes end - toMinutes start
toMinutes :: String -> Int
toMinutes (h:h':_:m:m':_) =
(read (h : h' : []) :: Int) * 60 + (read (m : m' : []) :: Int)
main :: IO ()
main =
listToMaybe <$> getArgs >>= \file ->
case file of
Just file' -> do
entries <- parse <$> readFile file'
mapM_ putStrLn (map formatRepEntry $ generateReport entries)
Nothing -> putStrLn "File does not exist"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment