Problem Statement
The professor is conducting a course on Discrete Mathematics to a class of N students. He is angry at the lack of their discipline, and he decides to cancel the class if there are fewer than K students present after the class starts.
Given the arrival time of each student, your task is to find out if the class gets cancelled or not.
Input Format
The first line of the input contains T, the number of test cases. Each test case contains two lines. The first line of each test case contains two space-separated integers, N and K. The next line contains N space-separated integers, \$a_1,a_2,...,a_N\,ドル representing the arrival time of each student.
If the arrival time of a given student is a non-positive integer (\$a_i≤0\$), then the student enters before the class starts. If the arrival time of a given student is a positive integer (\$a_i>0\$), the student enters after the class has started.
Output Format
For each testcase, print "YES" (without quotes) if the class gets cancelled and "NO" (without quotes) otherwise.
Constraints
$$\begin{align} 1&≤T≤10,\\ 1&≤N≤1000,\\ 1&≤K≤N,\\ −100&≤a_i≤100, \text{where}\ i∈[1,N] \end{align}$$
Note
If a student enters the class exactly when it starts (\$a_i=0\$), the student is considered to have entered before the class has started.
Sample Input
2 4 3 -1 -3 4 2 4 2 0 -1 2 1
Sample Output
YES NO
Solution
def is_on_time(a):
return a <= 0
def class_cancelled(expected, arrival_times):
actual = map(lambda x: 1 if is_on_time(x) else 0, arrival_times).count(1)
return actual >= expected
def read_int():
return int(raw_input())
def read_ints():
return map(int, raw_input().strip().split())
if __name__ == '__main__':
T = read_int()
for _ in xrange(T):
N, K = read_ints()
A = read_ints()
print "NO" if class_cancelled(K, A) else "YES"
3 Answers 3
def class_cancelled(expected, arrival_times):
....
return actual >= expected
print "NO" if class_cancelled(K, A) else "YES"
class_cancelled
is a misnomer. It in fact computes a class_not_cancelled
condition: class should be cancelled when actual < expected
. Also the problem asks to print "Yes" when the class gets cancelled. Funny how two wrongs make it right.
The roll call can be accomplished using sum()
, which is the simplest way to count True
values:
def on_time_attendees(arrival_times):
return sum(t <= 0 for t in arrival_times)
As @vnp mentioned, class_cancelled()
actually does the opposite of what its name suggests. Now that you have introduced that confusion, the best way out may be to eliminate that function entirely.
for test_case in xrange(read_int()):
n, k = read_ints()
print("YES" if on_time_attendees(read_ints()) < k else "NO")
-
\$\begingroup\$
on_time_attendees
really a good name. I wonder how can I come up with that kind of names? \$\endgroup\$CodeYogi– CodeYogi2015年10月06日 05:08:54 +00:00Commented Oct 6, 2015 at 5:08 -
2\$\begingroup\$ "There are only two hard things in Computer Science: cache invalidation and naming things." Writing good code takes practice, I guess. \$\endgroup\$200_success– 200_success2015年10月06日 05:39:20 +00:00Commented Oct 6, 2015 at 5:39
Readability Counts
I challenge you to come back in a week and tell me what this code does:
def class_cancelled(expected, arrival_times):
actual = map(lambda x: 1 if is_on_time(x) else 0, arrival_times).count(1)
return actual >= expected
First of all, you could rewrite it without the lambda
by doing:
actual = map(is_on_time, arrival_times).count(True)
but, while more terse, that doesn't actually aid reability either. You could drop the count()
by instead using filter()
:
actual = len(filter(is_on_time, arrival_times))
but that's not really any better either.
Both are also inefficient. We're constructing a new list based on arrival_times
, and then iterating over it again to count the 1
s or True
s instead of counting them as we go. We can use a generator expression for that:
def class_cancelled(expected, arrival_times):
actual = sum(1 for t in arrival_times
if is_on_time(t))
return actual >= expected
Or, even better:
def number_on_time(arrival_times):
return sum(1 for t in arrival_times
if t <= 0)
...
print "NO" if number_on_time(A) >= K else "YES"
I wouldn't put the non-positive check in its own function. This is clear enough as it is.
If you want to refactor anything, I would add something like this to your toolkit:
def count_if(iterable, pred):
return sum(1 for x in iterable if pred(x))
So that:
def number_on_time(arrival_times):
return count_if(arrival_times, lambda t: t <= 0)
That is easily understood.
-
\$\begingroup\$ Could you please elaborate a little on why you consider that
len(filter(is_on_time, arrival_times))
is such unreadable when comparedsum(1 for t in arrival_times if t <= 0)
? \$\endgroup\$Borsunho– Borsunho2015年10月05日 20:10:04 +00:00Commented Oct 5, 2015 at 20:10 -
\$\begingroup\$ Because I find your answer quite misleading. Order of reading that happens to be similar to English sentence expressing the idea doesn't make this operation any more readable. To understand what
sum
is for reader needs to read comprehension first, just like with functional version one needs to readfilter
call before he understands whatlen
really does. One could agree that later version is more 'visually pleasing', 'idiomatic' or 'pythonic', but readability as in 'ease of understanding' is pretty much the same. \$\endgroup\$Borsunho– Borsunho2015年10月05日 21:21:34 +00:00Commented Oct 5, 2015 at 21:21 -
\$\begingroup\$ @Borsunho I don't know how you group 'visually pleasing', 'idiomatic', and 'pythonic' as somehow separate categories from 'ease of understanding'. The fact that you believe it fits the first three pretty much definitely states that it fits the latter one. But YMMV. \$\endgroup\$Barry– Barry2015年10月05日 21:23:43 +00:00Commented Oct 5, 2015 at 21:23
Explore related questions
See similar questions with these tags.