#1

# Code Challenge 20: August 23, 2017

Every week, we feature the type of brain-teasing question that might be asked in a full-stack developer’s job interview at places such as Google and Facebook.

Variations of week’s challenge were reported to have been asked in interviews at Amazon:

### The Challenge

You’re training for a marathon and have a list of times in which you’ve completed your training runs. Write a function, `averageFinder` that will return the mean and mode of your race times. Make sure that you write your functions and find these answers from scratch – don’t use imported tools!

• Function name: `averageFinder`
• Input: an array with race times, each a natural number representing the minutes it took you to finish your run (you can presume that race times are rounded up to the nearest minute so we do not have to deal with seconds)
• Output: an array, with mean time and mode time (in that order)
• Example: `averageFinder([500, 450, 400, 400, 375, 350, 325, 300]) => [387.5, 400]`
• Please include the above sample input array in your submission as a test.
• Always remember to explain your code and the thought processes behind it!
• As always solutions using imports to do all the heavy lifting such as `itertools` will not be considered for the winner (and are not what interviewers are looking for) – you should write your functions from scratch.
• What if your interviewer had follow-up questions, for example asking for maximum, median, and minimum times instead of mean and mode? What if your input array did not have duplicate values? Don’t anticipate what exactly those follow-ups or changes may be, but try to write your code so that it is easily read, easily maintained, and can be adapted to potential modifications in the interviewer’s questioning.

### Intermediate difficulty

You’re not satisfied with just looking at the historical data for your marathon training – you want your program to reflect your continued progress, returning your best, worst, and average run times. Write a function, `timeKeeper` that will help you out. `timeKeeper` will take an input, `n` a positive integer representing the number of minutes it took you to complete your latest run, and then return an array of the following vital statistics about all of your runs to date:

• the longest time you’ve taken to date (`maxTime`)
• the shortest (best) time you’ve taken to date (`minTime`)
• the mean of all of your race times (`meanTime`)
• the mode of all of your race times (`modeTime`)
• the median of all of your race times (`medianTime`)
• function name: `timeKeeper`
• Input: a race time `n`, a natural number in minutes (you can presume that race times are rounded up to the nearest minute so we do not have to deal with seconds). Each time you insert a new time, `n`, it is added to an array that contains all of your historical race times.
• Output: an array, with longest time, shortest time, mean time, mode time and median time (in that order)
• Example: with an existing array of `[500, 450, 400, 400, 375, 350, 325, 300]` for your historical times and your new time of `320` to insert, `timeKeeper(320) => [500, 300, 380, 400, 375]`
• Please include this example array and insertion in your test submission to make it easier for others to assess.
• Always remember to explain your code and the thought processes behind it!
• Make sure to write everything from scratch!
• Interviewers often ask you for extra features or revisions after you’ve made the program, so for bonus points – can you also return whether or not (and by how much) your times are improving over time? You can presume that your array of race times is sorted by the time in which they were logged, with the first time you trained as the first entry in the array and the most recent time as the last entry in the array. You would show the value for improvements (or deterioration) of your times as the last entry in your results array, after the median.
• If you’d prefer to use a class that is acceptable too

### Hard Difficulty

Write `timeKeeper` as efficiently as possible (and try to include the bonus points question).

• Don’t forget to explain your submission just as you would do in a job interview setting!

#### `Reply` to this thread with a link to your code on repl.itand paste your properly formatted code to participate! Don’t just submit your code, remember to `explain` your solution, too! If you want to be considered as the winner, your function `must` have the `correct name` and provide `output in the format specified` above, you also need to abide by our other simple rules.

As always solutions using imports to do all the heavy lifting such as `itertools` will not be considered for the winner.

When including your repl.it link, please just give us the link and not the code preview! Just put a space before your URL so that the preview box doesn’t show – too many preview boxes can make the thread hard to read.

The fine print:

#4

Basic difficulty in Python. Mean is basic averaging, mode is calculated by implementing a hashmap and then finding the key with the largest value.

https://repl.it/KWzm/2

``````def averageFinder(times):
mean = sum(times)/float(len(times))

stats = {}
for x in times:
if x in stats:
stats[x] += 1
else:
stats[x] = 1

mode = max(stats,key=stats.get)

return mean,mode

times = [500, 450, 400, 400, 375, 350, 325, 300]
print averageFinder(times)
``````

Intermediate/hard difficulty in Python. Min/max use Python built-ins, mean and mode are calculated the same as in the basic difficulty version, median creates a temporary sorted array and returns the middle value or the mean of the two middle values, depending on array length.

https://repl.it/KXAm/1

``````class timeKeeper:

# Initialize with empty array if no arguments passed
def __init__(self,times = None):
if times is None:
self.times = []
else:
self.times = times

# Add a new time and return current stats
times.append(n)
return [self.max_time(), self.min_time(), self.mean_time(), self.mode_time(), self.median_time()]

def max_time(self):
return max(times)

def min_time(self):
return min(times)

def mean_time(self):
return sum(times)/float(len(times))

def mode_time(self):
stats = {}
for x in times:
if x in stats:
stats[x] += 1
else:
stats[x] = 1

return max(stats,key=stats.get)

def median_time(self):
sorted_times = sorted(times)
time_len = len(sorted_times)
if time_len % 2 == 0:
return sum(sorted_times[time_len/2-1:time_len/2+1])/2.0
else:
return sorted_times[time_len/2]

times = [500, 450, 400, 400, 375, 350, 325, 300]
tk = timeKeeper(times)
``````

#5

Basic using Ruby : https://repl.it/KXUg/0

#6

Hard + Bonus
repl: https://repl.it/KX5c/1

``````from typing import *

def timeKeeper(new_race_time: int) -> List:

historical_runs = list([500, 450, 400, 400, 375, 350, 325, 300])
historical_runs.append(new_race_time)

# initialization of values
max_time: int = 0
min_time: int = 10**6
mode_time: int = None

mode_count = dict()
sum_of_all = 0

# doing all the heavy lifting in a single pass over the run times
for run_time in historical_runs:

# MAX TIME CALCULATION
if run_time > max_time:
max_time = run_time

# MIN TIME CALCULATION
if run_time < min_time:
min_time = run_time

# accumulation of the sum of all numbers to be used for calculating the mean time
sum_of_all += run_time

# counting occurances of run times in a dict
mode_count[run_time] = mode_count.get(run_time, 0) + 1

# MEAN TIME CALCULATION
mean_time = float(sum_of_all / len(historical_runs))

# MODE TIME CALCULATION
occurrence = 0

for key, value in mode_count.items():

# searching for highest occurrence value in the dict. They key for this value will be the mode time
if value > occurrence:
occurrence = value
mode_time = key

# returning -1 in case of no duplicate values (occurrence <= 1)
if occurrence <= 1:
mode_time = -1

# IMPROVEMENT CALCULATION
improvements = RunImprovements.calculate_improvements(historical_runs)

# MEDIAN TIME CALCULATION
median_index = int(len(historical_runs) / 2)

# sorting the list of runs for the sake of median value calculation
historical_runs = list(sorted(historical_runs))
# I decided to sort it inplace to not use extra memory. In a real world
# scenario it might be worth to keep the original order of the list for clarity

# calculating median time in the cases of even and odd length of historical_runs list
if len(historical_runs) % 2 == 0:
median_time = float((historical_runs[median_index - 1] + historical_runs[median_index]) / 2)
else:
median_time = historical_runs[median_index]

return [max_time, min_time, mean_time, mode_time, median_time, improvements]

class RunImprovements:

def __init__(self, run_time, improved):

self.run_time: int = run_time
self.improved: bool = improved
self.improvement_rate: float = None

@staticmethod
def calculate_improvements(historical_runs):

runs: List['RunImprovements'] = list()

for index, run_time in enumerate(historical_runs):

if index == 0:
run = RunImprovements(run_time=run_time, improved=False)

else:
run = RunImprovements(run_time=run_time, improved=historical_runs[index] < historical_runs[index - 1])
if run.improved:
run.improvement_rate = float((historical_runs[index-1] / historical_runs[index]) - 1) * 100

runs.append(run)

return runs

def __repr__(self):

if self.improved:
return "Run time: %s  Time improved: %s  Improvement Rate %s %%" % (self.run_time, self.improved, round(self.improvement_rate, 1))
else:
return "Run time: %s  Time improved: %s" % (self.run_time, self.improved)

result = timeKeeper(320)
print(result[:-1])

for improvement in result[-1]:
print(improvement)

``````

Output

``````[500, 300, 380.0, 400, 375]
Run time: 500  Time improved: False
Run time: 450  Time improved: True  Improvement Rate 11.1 %
Run time: 400  Time improved: True  Improvement Rate 12.5 %
Run time: 400  Time improved: False
Run time: 375  Time improved: True  Improvement Rate 6.7 %
Run time: 350  Time improved: True  Improvement Rate 7.1 %
Run time: 325  Time improved: True  Improvement Rate 7.7 %
Run time: 300  Time improved: True  Improvement Rate 8.3 %
Run time: 320  Time improved: False
``````

#7

Hard Difficulty : Python 3.6 -

This challenge doesn’t need detailed explanation, though included in comments.
Time complexity of averageFinder() is O(n) and of creating a timeKeeper() object is O(n*log(n)) [due to sorting] whereas addition of new time in timeKeeper() is effectively O(n)

``````def averageFinder(raceTimes):             # O(N+K), simply O(N)
mean = 0
counts = {}                           # keeps count of race times
maxCount = 0                          # maximum occurance of a race time
for time in raceTimes:                # O(N)
mean += time
counts[time] = counts[time]+1 if time in counts else 1
if counts[time] > maxCount:
mode = time
maxCount = counts[time]
elif maxCount == counts[time] and time < mode:
mode = time
mean /= len(raceTimes)

return [mean, mode]

class timeKeeper:

@staticmethod
def insertIntoSortedList(sortedList, element):  # Best case O(1) worst case O(N+log(N)), i.e. O(N)
elementInserted = False
if len(sortedList) == 0:
sortedList.append(element)              # O(1)
elementInserted = True
elif sortedList[0] > element:
sortedList.insert(0, element)           # O(N)
elementInserted = True
elif sortedList[-1] < element:
sortedList.append(element)              # O(1)
elementInserted = True
if not elementInserted:
start = 0
end = len(sortedList)
while start <= end:                     # Binary search used to find place in sorted array, O(log(N))
mid = (start + end)//2
if sortedList[mid] == element:
sortedList.insert(mid, element)        # O(N)
elementInserted = True
break
elif sortedList[mid] > element:
end = mid - 1
else:
start = mid + 1
if not elementInserted:
if sortedList[mid] > element:
sortedList.insert(mid, element)       # O(N)
else:
sortedList.insert(mid + 1, element)   # O(N)
elementInserted = True

def __init__(self, timeList=None):             # Initialize all the values, worst case O(N*log(N)+N) i.e. O(N*log(N))
self.timeList = timeList if (not timeList is None) else []
if type(self.timeList) == int:
self.timeList = [self.timeList]
self.sortedTimeList = sorted(self.timeList)    # O(N*log(N))
self.__meanTime = None
self.__modeTime = None
self.__medianTime = None
self.__minTime = None
self.__maxTime = None
self.previous = None
self.counts = {}                     # keeps count of race times
mean = 0
maxCount = 0
for time in self.timeList:           # O(N), used to keep counts and calculate mean
mean += time
self.counts[time] = self.counts[time]+1 if time in self.counts else 1
if self.counts[time] > maxCount:
mode = time
maxCount = self.counts[time]
elif maxCount == self.counts[time] and time < mode:
mode = time
if (not timeList is None):           # Calculate max, min, mean, mode and median if race time/s as input is/are given
self.calculateAll(mean/len(self.timeList), mode)      # Mean, Mode already calculated

def record(self, newTime):               # add race time for new trial, O(N)
self.timeList.append(newTime)        # Adding new race time to the list
timeKeeper.insertIntoSortedList(self.sortedTimeList, newTime)
# Sorting the array is a must to find the median(atleast to my knowleadge), so instead of sorting race time list each time new value is added, I sort the list once during initialization and add new times in correct places in the sorted array
# In the earlier case i.e. sorting is O(N*log(N)) where inserting into sorted list is O(N)
self.counts[newTime] = self.counts[newTime]+1 if newTime in self.counts else 1      # increment its count by one
if self.__meanTime is None:
self.__maxTime = self.__minTime = self.__meanTime = self.__modeTime = self.__medianTime = newTime
return self
else:
self.previous = [self.__maxTime, self.__minTime, self.__meanTime, self.__modeTime, self.__medianTime]   # Store previous stats
trialsNo = len(self.timeList)
mean = newTime if self.previous[2] == newTime else (self.previous[2]*(trialsNo - 1) + newTime)/trialsNo       # O(1)
# Mean remains same if new time is equal to the mean
# Otherwise instead of getting the sum of all race times which is O(N), used previous sum and added new time to get the current sum which is O(1) and divided the sum by total race trials to get mean(average)
mode = newTime if ((self.counts[self.previous[3]] == self.counts[newTime] and newTime < self.previous[3]) or (self.counts[self.previous[3]] < self.counts[newTime])) else self.previous[3]           # O(1)
# the newly added race time becomes Mode if its count is greater than all other or if its count is maximum(maybe equal to others) and it is lowest of them all
# Otherwise it remains same as before
median = newTime if self.previous[4] == newTime else None                    # O(1)
# Mean, Mode and Median are calculated here for efficiency(reduce calculation, thus time)
self.calculateAll(mean, mode, median)
return self                          # print the stats

def examine(self):                       # inspect changes, included as BONUS
if self.previous == None:
print('Not enough evidence')
return
if self.previous[0] < self.__maxTime or self.previous[1] > self.__minTime:
print(f'New record for {"best" if self.previous[1] > self.__minTime else "worst"} time of {self.__minTime if self.previous[1] > self.__minTime else self.__maxTime} seconds recently added.')
if self.previous[2] > self.__meanTime:
print(f'Average race time is improved by {round(self.previous[2] - self.__meanTime, 2)} seconds and {round((100 - (self.__meanTime*100/self.previous[2])), 2)}% from last time')
else:
print(f'No recent improvement in race time.')

def history(self, getRaceTimes=False):
print('The following data shows improvement in positive seconds and negative for descent for all the race trials in seconds :-')
trialsNo = len(self.timeList)
print([(self.timeList[i] - self.timeList[i+1]) for i in range(trialsNo) if i < (trialsNo - 1)])
if getRaceTimes:
print(f'History of all race times in order => {self.timeList}')
return

def calculateAll(self, mean, mode, median=None):     # O(1)
trialsNo = len(self.timeList)                  # number of running trials
self.__meanTime = mean
self.__modeTime = mode

if not(median is None):
self.__medianTime = median
else:
if trialsNo > 2:                               # find median from middle of sorted list of race times
self.__medianTime = self.sortedTimeList[trialsNo//2] if trialsNo%2 else (self.sortedTimeList[trialsNo//2]+self.sortedTimeList[trialsNo//2 - 1])/2    # O(1)
else:
self.__medianTime = self.__meanTime        # if total recorded race times are less than 3, median and mean are equal

self.__maxTime = self.sortedTimeList[-1]           # O(1)
self.__minTime = self.sortedTimeList[0]            # O(1)

def __repr__(self):                           # return max, min, mean, mode and median of all recorded run times in same order
return str([self.__maxTime, self.__minTime, round(self.__meanTime, 3), self.__modeTime, self.__medianTime])

``````

https://repl.it/K0y1/13

I thought inserting an element in a list at particular index would be O(1) but it is actually O(n).

#8

Solution to basic difficulty in Java
https://repl.it/KX1l/27

``````/*The method mean_mode first calculates the mode of the array, i.e the number with the
maximum number of occurrences. If there are more than one such values, the number with
higher value will be the mode. If none of the values repeat, the largest number will be the
mode. Then it calculates the mean of the elements in the array.*/
class Main{
public static void mean_mode(int[] time) {
int mode = time[0];
int maxCount = 0;
int sum=0;
for (int i = 0; i < time.length; i++) {
int value = time[i];
int count = 1;
for (int j = 0; j < time.length; j++) {
if (time[j] == value) count++;
if (count > maxCount) {
mode = value;
maxCount = count;
}
}
}
for(int i=0;i<time.length;i++){
sum=sum+time[i];
}
float mean=(float)sum/(time.length);
System.out.print("["+mean+", "+mode+"]");
}
public static void main(String[] args) {
int[] time = new int[] {500, 450, 400, 400, 375, 350, 325, 300};
mean_mode(time);
}
}
``````

#9

Intermediate Solution
https://repl.it/K0IY

It uses ES6 JavaScript, and is broken down into tiny functions for easy maintainability/additions. The portion that makes it maintainable, is storing functions in a reusable manner as methods in an object named helpers. If there is any additional functionality required, more helper functions can be added to support anything else in the app.

Performance wise, I know the reduce calls are not so hot, but this is probably all the time I can contribute to this as of right now. I am sure it will also fail for other cases as well, but this is my final submission. Godspeed.

``````let historical = [500, 450, 400, 400, 375, 350, 325, 300]

const timeKeeper = (n, arr) => {
historical.push(n)

return [
helpers.longestTime(arr),
helpers.shortestTime(arr),
helpers.mean(arr),
helpers.mode(arr),
helpers.median(arr)
]
}

const helpers = {
total: function(arr) { return arr.reduce(this.sum) },
divide: function(a, b) { return a / b },
mean: function(arr) { return this.divide(this.total(arr), arr.length) },
median: function(arr) {
let sorted = arr.sort()
let i = Math.floor(sorted.length / 2)
return sorted[i]
},
mode: function(arr) {
return arr.reduce(
(a,b,i,arr) => (arr.filter(c=> c === a).length >= arr.filter(c => c === b).length) ? a : b,
null
)
},
longestTime: function(arr) {
return arr.reduce((prev,cur) => prev > cur ? prev : cur)
},
shortestTime: function(arr) {
return arr.reduce((prev,cur) => prev < cur ? prev : cur)
}
}

// Run the program
timeKeeper(320, historical)
``````

#10

https://repl.it/KY0V/1#Basic Challenge

#11

https://repl.it/KY2r/0 timeKeeper Intermediate difficulty

#13

Remember, entries that do not include preformatted code samples and explanation will not be considered. A REPL link alone will not make the cut.

#15

Aren’t the comments in the code enough?

#16

We want to see your code posted right here for easy readability. In the challenge prompt it says:

#17

timeKeeper Intermediate difficulty with bonus
I had to create a redirect link because it says I cannot post links to that host
http://bit.ly/Daniel_timeKeeperBonus

``````const timeKeeperList = [500, 450, 400, 400, 375, 350, 325, 300];
function timeKeeper(num) {
timeKeeperList.push(num);

const
s    = timeKeeperList.map(n => n).sort(), // s as in sorted
min  = s[0],                  // first element of a sorted list is the min
max  = s[s.length - 1],       // last  element of a sorted list is the max
mean = s.reduce((a, b) => a + b) / s.length, // sums all values and divides result by 2, mean

// the module of odd numbers by 2 always returns 1, which is evaluated as true on the ternary
// in that case, the median will be the middle element of the sorted list
// the module of odd numbers by 2 is always 0, which is evaluated as false on the ternary
// in that case it calculates the mean of the two middle elements
median = s.length % 2 ? s[~~(s.length / 2)] : (s[s.length / 2 - 1] + s[s.length / 2]) / 2,
temp = {};

// The numbers in the list will become unique keys in the hashTable temp
// the values of each key will be the numbers of occurrences of each key
s.forEach(n => temp[n]++ || (temp[n] = 1));
const
// sorts a list of keys by their values in a descending order
modeList = Object.keys(temp).sort((a, b) => temp[b] - temp[a]),
// The mode only exists if the top value is greater that the previous one
mode = modeList[0] > modeList[1] ? +modeList[0] : undefined;

// declaring res outside just because I want to use a single line
// arrow function for to map the array
let res;

const report = timeKeeperList
// maps the array with the differences between the current value and the next
// if the diference is not 0 it will return the negative value of that difference
// that will show when the times are increasing or decreasing
.map((v, i, list) => (res = v - list[i + 1]) && -res || res)

// the last element of the  report is always NaN, hence the removal of it
return [max, min, mean, mode, median, report.slice(0, report.length - 1)];
}

timeKeeper(320); // [ 500, 300, 380, 400, 375, [ -50, -50, 0, -25, -25, -25, -25, 20 ] ]
``````

#18

timeKeeper Hard difficulty with bonus
This is basically some improvement techniques applied to the previous post
The performance is around 30% when compared to the pretty version of it.

Performatic code is usually not pretty

The optimizations are done basically by replacing good looking helpers and syntaxes
by old approaches.
E.g:

• array.map replaced by a a for loop
• let replaced by var

When the comments are removed the optimizer might work better and improve
it a little further.

I had to create a redirect link because it says I cannot post links to that host
https://goo.gl/yWE5Hg

``````const timeKeeperList = [500, 450, 400, 400, 375, 350, 325, 300];
function timeKeeper(num) {
timeKeeperList.push(num);
// cloning timeKeeperList
const
// pre-alocation with arrays is faster than .push
// for performance I use that aproach since I know
// beforehand the final size of my array
s = new Array(timeKeeperList.length),
temp = {},
// this variable will save a call to
// Object.keys(temp) later on
uniqueKeys = [];

var
i   = 0,
sum = 0;
// array.map is slow
// older versions of node.js let is slower than var
for (; i < s.length; i++) {
// shallow cloning and sum at once
sum += (s[i] = timeKeeperList[i]);

// The numbers in the list will become unique keys in the hash table temp
// the values of each key will be the numbers of occurrences of each key
// this line creates or increases the value of a given key
if (!temp[s[i]]++) {
temp[s[i]] = 1;
uniqueKeys.push(s[i]);
}
}

// sorts a list of keys by their values in a descending order
uniqueKeys.sort((a, b) => temp[b] - temp[a]);

// sorts the shallow cloned array
s.sort();

const
min  = s[0],            // first element of a sorted list is the min
max  = s[s.length - 1], // last  element of a sorted list is the max
mean = sum / s.length,  // sums all values and divides result by 2, mean

// the module of odd numbers by 2 always returns 1, which is evaluated as true on the ternary
// in that case, the median will be the middle element of the sorted list
// the module of odd numbers by 2 is always 0, which is evaluated as false on the ternary
// in that case it calculates the mean of the two middle elements
median = s.length % 2 ? s[~~(s.length / 2)] : (s[s.length / 2 - 1] + s[s.length / 2]) / 2,

// The mode only exists if the top value is greater that the previous one
mode = temp[uniqueKeys[0]] > temp[uniqueKeys[1]] ? +uniqueKeys[0] : undefined,

// creates the report array with size 1 less than the
// list of all recorded times for obvious reasons
report = new Array(timeKeeperList.length - 1);

// calculates the distances in minutes between a recorded time and its next
// if the diference is not 0 it will return the negative value of that difference
for (var ix = 0; ix < report.length; ix++) {
report[ix] = -(timeKeeperList[ix] - timeKeeperList[ix + 1]) || 0;
}

return [max, min, mean, mode, median, report];
}

timeKeeper(320); // [ 500, 300, 380, 400, 375, [ -50, -50, 0, -25, -25, -25, -25, 20 ] ];
``````

#19

Refactored my code into a class type thing . .
Python 3.6 btw

``````from typing import *
from collections import defaultdict

class TimeKeeper:

def __init__(self, new_race_time: int):

# Data Structures
self.historical_race_data = list([500, 450, 400, 400, 375, 350, 325, 300])
self.historical_race_data.append(new_race_time)
self.sorted_race_data = list(sorted(self.historical_race_data))

# Caching of values that will be produced by the pre processor and later
# accessed by the getter properties
self.__max__: int = 0
self.__min__: int = 10 ** 6
self.__mode__: int = None
self.__mode_count__: DefaultDict = defaultdict(int)
self.__sum__: int = 0

# Doing all the heavy lifting in a single pass over the race times
self.pre_process()

def pre_process(self):

for race_time in self.historical_race_data:

# MAX TIME CALCULATION
if race_time > self.__max__:
self.__max__ = race_time

# MIN TIME CALCULATION
if race_time < self.__min__:
self.__min__ = race_time

# accumulation of the sum of all numbers to be used for calculating the mean time
self.__sum__ += race_time

# counting occurances of race times in a dict
self.__mode_count__[race_time] += 1

self.historical_race_data.append(new_race_time)

if update:
self.sorted_race_data = list(sorted(self.historical_race_data))
self.pre_process()

@property
def min(self) -> int:
return self.__min__

@property
def max(self) -> int:
return self.__max__

@property
def mean(self) -> float:
return float(self.__sum__ / len(self.historical_race_data))

@property
def mode(self) -> int:
occurrence = 0

for key, value in self.__mode_count__.items():

# searching for highest occurrence value in the dict. They key for this value will be the mode time
if value > occurrence:
occurrence = value
self.__mode__ = key

# returning -1 in case of no duplicate values (occurrence <= 1)
if occurrence <= 1:
self.__mode__ = -1

return self.__mode__

@property
def improvements(self) -> List['Improvements']:
return Improvements.calculate_improvements(self.historical_race_data)

@property
def median(self) -> int:
median_index = int(len(self.sorted_race_data) / 2)

# calculating median time in the cases of even and odd length of sorted_race_data list
if len(self.sorted_race_data) % 2 == 0:
median_time = float((self.sorted_race_data[median_index - 1] + self.sorted_race_data[median_index]) / 2)
else:
median_time = self.sorted_race_data[median_index]

return median_time

@property
def result(self) -> List:
return list([self.max, self.min, self.mean, self.mode, self.median, self.improvements])
``````
``````class Improvements:

def __init__(self, race_time, improved):

self.race_time: int = race_time
self.improved: bool = improved
self.improvement_rate: float = None

@staticmethod
def calculate_improvements(historical_race_data: List[int]) -> List['Improvements']:

races: List['Improvements'] = list()

for index, race_time in enumerate(historical_race_data):

# catching index 0 because we will not be able to look at the previous index in this case
if index == 0:
race = Improvements(race_time=race_time, improved=False)

# comparing current index to previous index in order to determine if we have improved and by how much
else:
race = Improvements(race_time=race_time, improved=historical_race_data[index] < historical_race_data[index - 1])
if race.improved:
race.improvement_rate = float((historical_race_data[index - 1] / historical_race_data[index]) - 1) * 100

races.append(race)

return races

def __repr__(self):

if self.improved:
return "Race time: %s  Time improved: %s  Improvement Rate %s %%" % (self.race_time, self.improved, round(self.improvement_rate, 1))
else:
return "Race time: %s  Time improved: %s" % (self.race_time, self.improved)
``````

Execution

``````time_keeper = TimeKeeper(320)
result = time_keeper.result

print(result[:-1])

for improvement in result[-1]:
print(improvement)
``````

Output

``````[500, 300, 380.0, 400, 375]
Race time: 500  Time improved: False
Race time: 450  Time improved: True  Improvement Rate 11.1 %
Race time: 400  Time improved: True  Improvement Rate 12.5 %
Race time: 400  Time improved: False
Race time: 375  Time improved: True  Improvement Rate 6.7 %
Race time: 350  Time improved: True  Improvement Rate 7.1 %
Race time: 325  Time improved: True  Improvement Rate 7.7 %
Race time: 300  Time improved: True  Improvement Rate 8.3 %
Race time: 320  Time improved: False
``````

#20

@danieloduffy You have made a mistake in description of basic challenge. In example you have used timeKeeper() as input whereas the basic challenge only deals with averageFinder(). Please see to that.

#21

Basic difficulty in Python 3.6:

• Mean is calculated by dividing the sum by the number of race times.
• Mode is calculated by finding the number of occurrences for each time.
https://repl.it/KZqY/0
``````def averageFinder(times):
mean = sum(times) / len(times)  # averaging
set_times = sorted(set(times))  # eliminate duplication
num_occur = [times.count(t) for t in set_times]  # list comprehension
mode_index = num_occur.index(max(num_occur))
mode = set_times[mode_index]

return [mean, mode]

race_times = [500, 450, 400, 400, 375, 350, 325, 300]
print(averageFinder(race_times))
``````

#22

The Basic difficulty in JavaScript:
https://repl.it/KZtm/1

``````function averageFinder(times){
var prom;
var mode = times[0];
var max = 0;
var sum=0;
for(var i = 0; i<times.length; i++){
sum += times[i];
var value = times[i];
var cont = 1;
// to find the mode
for (var j = 0; j<times.length; j++) {
if (times[j] == value) cont++;
if (cont > max) {
mode = value;
max = cont;
}
}
}
prom = sum/times.length;
return [prom, mode];
}

var times = [500, 450, 400, 400, 375, 350, 325, 300];

console.log(averageFinder(times));
``````

#23

Basic Challenge. The comments explain the logic
http://bit.ly/2gcotDW

``````function averageFinder(s) {
const mean = s.reduce((a, b) => a + b) / s.length;
const temp = {};
// The numbers in the list will become unique keys in the hashTable temp
// the values of each key will be the numbers of occurrences of each key
s.forEach(n => temp[n]++ || (temp[n] = 1));
// sorts a list of keys by their values in a descending order
const modeList = Object.keys(temp).sort((a, b) => temp[b] - temp[a]);
// The mode only exists if the top value is greater that the previous one
const mode = modeList[0] > modeList[1] ? +modeList[0] : undefined;

return [mean, mode];
}

averageFinder([500, 450, 400, 400, 375, 350, 325, 300]); // [ 387.5, 400 ]
``````

Same code with no comments, concise and minimal

``````function averageFinder(s) {
const mean = s.reduce((a, b) => a + b) / s.length;
const temp = {};

s.forEach(n => temp[n]++ || (temp[n] = 1));
const modeList = Object.keys(temp).sort((a, b) => temp[b] - temp[a]);
const mode = modeList[0] > modeList[1] ? +modeList[0] : undefined;

return [mean, mode];
}
``````

#24

Whoops, thanks for pointing that out (sorry I made this at like 2am under the influence of coffee, just like all good startup things)