Last active
April 22, 2022 20:02
-
-
Save nkhil/bab532a2f8fcb1d3acf79cd4e0a8309b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import never from 'never' | |
type ParsedLogs = Array<[string, string]> | |
type GroupedLogs = { | |
[K: string]: Array<string> | |
} | |
export default function main(logs: string) { | |
const parsedLogs = parseAndNormaliseLogs(logs) | |
const groupedLogs = groupCalls(parsedLogs) | |
const mostCalledNumber = findMostCalledNumber(groupedLogs) | |
return calculateTotalBill({ | |
logs: groupedLogs, | |
mostCalledNumber, | |
}) | |
} | |
function calculateTotalBill({ | |
logs, | |
mostCalledNumber | |
}: { | |
logs: GroupedLogs, | |
mostCalledNumber: string, | |
}): number { | |
const FIVE_MINUTES = 5 * 60 | |
return Object.entries(logs).reduce((totalBill, [phoneNumber, timestamps]) => { | |
if (phoneNumber !== mostCalledNumber) { | |
totalBill += timestamps.reduce((totalCostOfCall, timestamp) => { | |
const timeInSeconds = calculateSecondsGivenTimestamp(timestamp) | |
switch (true) { | |
case (timeInSeconds < FIVE_MINUTES): | |
totalCostOfCall += (timeInSeconds * 3) | |
break; | |
default: | |
const startedMinutes = Math.ceil(timeInSeconds / 60) | |
totalCostOfCall += 150 * startedMinutes | |
break; | |
} | |
return totalCostOfCall | |
}, 0) | |
} | |
return totalBill | |
}, 0) | |
} | |
function parseAndNormaliseLogs(logs: string): ParsedLogs { | |
const parsed = logs.split('\n').map(log => log.split(',')) as ParsedLogs | |
return normaliseLogs(parsed) | |
} | |
function normaliseLogs(logs: ParsedLogs): ParsedLogs { | |
const lastElementIndex = logs.length - 1 | |
const lastElement = logs[lastElementIndex] ?? never() | |
if (lastElement[0] === '') return logs.slice(0, -1) | |
return logs | |
} | |
function groupCalls(logs: ParsedLogs): GroupedLogs { | |
return logs.reduce((acc, val) => { | |
const [ timestamp, phoneNumber ] = val | |
if (!acc.hasOwnProperty(phoneNumber)) { | |
acc[phoneNumber] = [timestamp] | |
} else { | |
(acc[phoneNumber] ?? never()).push(timestamp) | |
} | |
return acc | |
}, {} as GroupedLogs) | |
} | |
function calculateSecondsGivenTimestamp(timestamp: string): number { | |
const [hours, minutes, seconds] = timestamp.split(':') | |
return Number(hours) * 60 * 60 + Number(minutes) * 60 + Number(seconds) | |
} | |
function convertToNumber(phoneNumber: string): number { | |
return Number(phoneNumber.replace(/-/g, '')) | |
} | |
function numberWithSmallestNumericValue(numberOne: string, numberTwo: string): string { | |
if (convertToNumber(numberOne) < convertToNumber(numberTwo)) return numberOne | |
return numberTwo | |
} | |
function calculateTotalSeconds(timestamps: Array<string>): number { | |
return timestamps.reduce((acc, timestamp) => { | |
acc = acc + calculateSecondsGivenTimestamp(timestamp) | |
return acc | |
}, 0) | |
} | |
function findMostCalledNumber(logs: GroupedLogs): string { | |
let largestTotal = 0 | |
return Object.keys(logs).reduce((acc, phoneNumber) => { | |
const totalSeconds = calculateTotalSeconds(logs[phoneNumber] ?? never()) | |
if ((totalSeconds ?? never()) > largestTotal) { | |
acc = phoneNumber | |
largestTotal = (totalSeconds ?? never()) | |
} else if ((totalSeconds ?? never()) === largestTotal) { | |
acc = numberWithSmallestNumericValue(phoneNumber, acc) | |
} | |
return acc | |
}, '') | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment