25

first question here, so i will get right to it:

using python 2.7

I have a dictionary of items, the keys are an x,y coordinate represented as a tuple: (x,y) and all the values are Boolean values.

I am trying to figure out a quick and clean method of getting a count of how many items have a given value. I do NOT need to know which keys have the given value, just how many.

there is a similar post here: How many items in a dictionary share the same value in Python, however I do not need a dictionary returned, just an integer.

My first thought is to iterate over the items and test each one while keeping a count of each True value or something. I am just wondering, since I am still new to python and don't know all the libraries, if there is a better/faster/simpler way to do this.

thanks in advance.

Community
  • 1
  • 1
jguerra
  • 303
  • 1
  • 4
  • 7

2 Answers2

36

This first part is mostly for fun -- I probably wouldn't use it in my code.

sum(d.values())

will get the number of True values. (Of course, you can get the number of False values by len(d) - sum(d.values())).


Slightly more generally, you can do something like:

sum(1 for x in d.values() if some_condition(x))

In this case, if x works just fine in place of if some_condition(x) and is what most people would use in real-world code)

OF THE THREE SOLUTIONS I HAVE POSTED HERE, THE ABOVE IS THE MOST IDIOMATIC AND IS THE ONE I WOULD RECOMMEND


Finally, I suppose this could be written a little more cleverly:

sum( x == chosen_value for x in d.values() )

This is in the same vein as my first (fun) solution as it relies on the fact that True + True == 2. Clever isn't always better. I think most people would consider this version to be a little more obscure than the one above (and therefore worse).

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • great. that is exactly what i wanted. i would upvote but i can't because its my first post and i have no rep. i think i marked the answer helpful though :) – jguerra Nov 19 '12 at 21:25
  • @RocketDonkey you had a valid answer though - you should have left it :) – Jon Clements Nov 19 '12 at 21:29
  • I still prefer `sum(1 for i in something if i)` though... (and what are you doing with `==True` @mgilson) !? – Jon Clements Nov 19 '12 at 21:32
  • just out of curiosity, why wouldn't you use the first example: sum(d.values()) in your code? – jguerra Nov 19 '12 at 22:03
  • @JonClements I was trying to think of a way to make it a bit different - I'll repost with an inferior (but slightly different!) approach :) – RocketDonkey Nov 19 '12 at 22:04
  • @jguerra -- It doesn't generalize well to other conditions. It also really limits your values to booleans or `1` and `0` which is unpythonic. – mgilson Nov 19 '12 at 22:12
  • @JonClements -- Sorry, I was playing around a little 0:^) -- I've added (hopefully very clearly) which version I think is the best. On the other hand, while I do think it's the best answer there, I've never really liked the `sum(1 for _ in ... if ...)` idiom. It just seems like it's too round-about, but it is definitely the most common. – mgilson Nov 19 '12 at 22:13
  • @mgilson what is grinding is `if i == True` :( either `i is True` or `i` :) – Jon Clements Nov 19 '12 at 22:19
  • @JonClements -- Oh, I see what you're saying now ... well I wanted to put something in there that would generalize nicely to arbitrary conditional expressions for the benefit of OP. You're absolutely correct that the `== True` is completely unnecessary for this example. – mgilson Nov 19 '12 at 22:27
11

If you want a data structure that you can quickly access to check the counts, you could try using a Counter (as @mgilson points out, this relies on the values themselves being hashable):

>>> from collections import Counter
>>> d = {(1, 2): 2, (3, 1): 2, (4, 4): 1, (5, 6): 4}
>>> Counter(d.values())
Counter({2: 2, 1: 1, 4: 1})

You could then plug in a value and get the number of times it appeared:

>>> c = Counter(d.values())
>>> c[2]
2
>>> c[4]
1
RocketDonkey
  • 36,383
  • 7
  • 80
  • 84