From 0d22446c1ac6401a8d0de0dea9957892518a7d8a Mon Sep 17 00:00:00 2001 From: Vahagn Khachatryan Date: Thu, 1 Aug 2019 13:55:40 +0100 Subject: [PATCH] MAN AHL interview --- puzzles/interviews/man_AHL/rand_num_next.py | 72 +++++++++++++++++++++ puzzles/interviews/man_AHL/sql_query.txt | 23 +++++++ 2 files changed, 95 insertions(+) create mode 100644 puzzles/interviews/man_AHL/rand_num_next.py create mode 100644 puzzles/interviews/man_AHL/sql_query.txt diff --git a/puzzles/interviews/man_AHL/rand_num_next.py b/puzzles/interviews/man_AHL/rand_num_next.py new file mode 100644 index 0000000..7581f4e --- /dev/null +++ b/puzzles/interviews/man_AHL/rand_num_next.py @@ -0,0 +1,72 @@ +import random +import bisect + +class RandomGen(object): + + def __init__(self, random_nums, probabilities): + assert len(random_nums), 'Random number list is empty.' + assert len(random_nums) == len(probabilities), 'Random numbers and probabilities do not match.' + assert abs(1. - sum(probabilities)) < 0.0000001, 'Probabilities do not sum to 1.' + + # Values that may be returned by next_num() + self._random_nums = random_nums + # Probability of the occurence of random_nums. + # Actually we create range table here, such that all random numbers + # ranging from (tbl[i-1],tbl[i]] map to random_number[i] + self._range_table = probabilities + for i in range(1,len(self._range_table)): + self._range_table[i] += self._range_table[i-1] + # All random numbers which are not in any range will map + # to last _random_num. Therefore there is no point to have + # last _random_num probability range in the table. + self._range_table.pop() + + + def next_num(self): + """ + Returns one of the randomNums. When this method is called + multiple times over a long period, it should return the + numbers roughly with the initialized probabilities. + """ + r = random.random() + return self._random_nums[bisect.bisect_left(self._range_table, r)] + + +def test_init(random_nums, probabilities): + try: + rg = RandomGen(random_nums, probabilities) + except AssertionError as e: + return + assert False, "Had to be assert, but no assert could be detected." + + +def test(input, rep_count = 1000): + generate_stat = { _1 : 0 for _1,_ in input.items() } + rg = RandomGen([key for key in input.keys()], [val for val in input.values()]) + for i in range(rep_count): + generate_stat[rg.next_num()] += 1 + + for rnum, rnum_stat in generate_stat.items(): + stat_prob = rnum_stat/rep_count + orig_prob = input[rnum] + print('{}: orig: {} actual: {}'.format(rnum, orig_prob, stat_prob)) + print('') + + +if __name__ == '__main__': + test_init([], []) # Empty list of numbers not allowed + test_init([1, 2], [1. ]) # Probabilities don't match + test_init([1, 2], [ 0.1, 0.1]) # Probabilities don't sum to 1. + test({0 : 0.5, + 1 : 0.25, + 2 : 0.25 }) + test({-1 : 0.01, + 0 : 0.3, + 1 : 0.58, + 2 : 0.1, + 3 : 0.01 }, 100) + test({-1 : 0.01, + 0 : 0.3, + 1 : 0.58, + 2 : 0.1, + 3 : 0.01 }, 100000) diff --git a/puzzles/interviews/man_AHL/sql_query.txt b/puzzles/interviews/man_AHL/sql_query.txt new file mode 100644 index 0000000..c47670c --- /dev/null +++ b/puzzles/interviews/man_AHL/sql_query.txt @@ -0,0 +1,23 @@ +I can imagine that the query should be something like this. But my SQL is not very good. + +SELECT + p.product_id as product_id, + p.name as name, + o.quantity as quantity +FROM + product p + JOIN ( + SELECT + product_id, + SUM(quantity) as quantity + FROM + order + WHERE + dispatch_date > DATEADD(year, -1, GETDATE()) + GROUP BY + product_id + ) o ON o.product_id = p.product_id +WHERE + p.available_from < DATEADD(month, -1, GETDATE()) + AND o.quantity < 10 +