0

I'd like to iterate over a subset of a dictionary to find the minimum value in the subset. I can use a generator expression to get the value:

>>> S = {'a', 'c'}
>>> D = {'a': 2, 'b': 0, 'c': 1, 'd': 3}
>>> min(D[k] for k in S)
1

To get the associated keys, I guess this is possible:

>>> subset_min = min(D[k] for k in S)
>>> [k for k, v in D.iteritems() if v == subset_min]
['c']

But surely there's a way that wouldn't require searching the dictionary again? I was hoping for something like min(D, key=D.get) as discussed here, but I can't see how to apply it in this case.

Community
  • 1
  • 1
hnakhoul
  • 3
  • 3
  • 1
    If there are two keys at the minimum value, will you need them both, or will any suffice? – DSM Aug 14 '13 at 19:01

2 Answers2

5
min(S, key=D.get)

Surprisingly simple.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • You can also do `D[min(S, key=D.get)]` – dawg Aug 14 '13 at 19:06
  • @drewk: Sure, if you only want the value, but the question was about how to get the key. – user2357112 Aug 14 '13 at 19:10
  • Whoa, very nice. I'm learning not to be too surprised when it's simpler than I expect in Python. Could I do something similar for a more general expression involving the values, e.g. finding the key that minimizes `2*D[k]+1`? Or would unutbu's answer give the best approach for that? – hnakhoul Aug 14 '13 at 21:10
  • `min(S, key=lambda k: 2*D[k]+1)`. `lambda` is pretty versatile, but there's usually a better way. (Note that in this case, minimizing `D[k]` minimizes `2*D[k]+1`, so you could still use `key=D.get` anyway.) – user2357112 Aug 14 '13 at 21:13
1
min_val, min_key = min((D[k], k) for k in S)

This will give you a key which is associated with the minimum value, but it will not tell you if there are multiple such keys.

Or, you could find the key first, and then access the associated value:

min_key = min(S, key=D.get)
min_val = D[min_key]

If you want to collect all the keys in D associated with subset_min, then you'll have it iterate over all of D, as you posted.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677