I have two lists of marks for the same set of students. For example:
JavaScript
x
3
1
A = [22, 2, 88, 3, 93, 84]
2
B = [66, 0, 6, 33, 99, 45]
3
If I accept only students above a threshold according to list A then I can look up their marks in list B. For example, if I only accept students with at least a mark of 80 from list A then their marks in list B are [6, 99, 45].
I would like to compute the smallest threshold for A which gives at least 90% of students in the derived set in B getting at least 50. In this example the threshold will have to be 93 which gives the list [99] for B.
Another example:
JavaScript
1
3
1
A = [3, 36, 66, 88, 99, 52, 55, 42, 10, 70]
2
B = [5, 30, 60, 80, 80, 60, 45, 45, 15, 60]
3
In this case we have to set the threshold to 66 which then gives 100% of [60, 80, 80, 60] getting at least 50.
Advertisement
Answer
This is an O(nlogn + m) approach (due to sorting) where n is the length of A
and m is the length of B
:
JavaScript
1
22
22
1
from operator import itemgetter
2
from itertools import accumulate
3
4
5
def find_threshold(lst_a, lst_b):
6
# find the order of the indices of lst_a according to the marks
7
indices, values = zip(*sorted(enumerate(lst_a), key=itemgetter(1)))
8
9
# find the cumulative sum of the elements of lst_b above 50 sorted by indices
10
cumulative = list(accumulate(int(lst_b[j] > 50) for j in indices))
11
12
for i, value in enumerate(values):
13
# find the index where the elements above 50 is greater than 90%
14
if cumulative[-1] - cumulative[i - 1] > 0.9 * (len(values) - i):
15
return value
16
17
return None
18
19
20
print(find_threshold([22, 2, 88, 3, 93, 84], [66, 0, 6, 33, 99, 45]))
21
print(find_threshold([3, 36, 66, 88, 99, 52, 55, 42, 10, 70], [5, 30, 60, 80, 80, 60, 45, 45, 15, 60]))
22
Output
JavaScript
1
3
1
93
2
66
3