mmmdreg
mmmdreg

Reputation: 6618

Pythonic proportion calculation of two conditions

Here's a really simple question regarding pythonic coding.

Given a list, if you want to calculate the proportion of items satisfying (A and B), out of those satisfying (A), a natural solution would be:

Imagine the list is of integers, condition A is (>3), condition B is (>5)

count = 0
correct = 0

for item in items:
  if item > 3:
    count += 1

    if item > 5:
      correct += 1

score = float(correct) / count
print '%.2f' % score

An alternative solution:

count = len([1 for i in items if i > 3])
correct = len([1 for i in items if i > 5])

score = float(correct) / count
print '%.2f' % score

The alternative looks sexier to me, though it loops through items twice and is not efficient. Is there an accepted pythonic solution to this common scenario or is the first solution good enough?

Thanks.

Upvotes: 1

Views: 3342

Answers (3)

Apalala
Apalala

Reputation: 9244

This is not a general solution, but one based on your question and the sample answer.

If you know the relationship between the two conditions, then you don't have to traverse the sequence twice:

gt3 = [x for x in items if x > 3]
count = len(gt3)
correct = sum(x > 5 for x in gt3)

An efficient, more general, and still pythonic solution could be:

count, correct = map(sum, zip(*((x > 3, x > 5) for x in items)))

The conditions of greater than 3 and 5 can be replaced by any other conditions.

Upvotes: 1

Jochen Ritzel
Jochen Ritzel

Reputation: 107746

Your (alternate) solution is great, except for this small change:

count = sum(1 for i in items if i > 3)
correct = sum(1 for i in items if i > 5)

score = float(correct) / count
print '%.2f' % score

The syntax that looks like a list comprehension without the brackets is called a generator expression.

I'm not aware of any readable way to get a solution without iterating over the list twice, other than the one you already have. I'd still go with the solution above, unless a profiler tells me I have to speed this up.

Upvotes: 6

crazy
crazy

Reputation: 1

from itertools import groupby
li={x:len(list(y))for x,y in groupby(l,lambda x:2 if x>5 else 1 if x>3 else 0)}
print(li[2]/(li[1]+li[2]))

python3.1

Upvotes: 0

Related Questions