Reputation: 41
I have a dictionary and I would like to get the key whose value is the minimum nonzero.
E.g. given the input:
{1:0, 2:1, 3:2}
It would return 2.
Upvotes: 4
Views: 3194
Reputation: 4606
Solution
some_dict = {1:0, 2:1, 3:2}
compare = []
for k, v in some_dict.items():
if k != 0:
compare.append(k)
x = min(compare)
print(x)
I just appended
all the non-zero keys
to a list
(compare
) and then applied min(compare)
We can plug x
back in and check that it is pointing to the key 1
which is the smallest non-zero key
and that returns it's value
which is 0
>>> print(some_dict[x])
>>> 0
Upvotes: 0
Reputation: 2244
print(min(i for i in dictionary if dictionary[i] != 0))
this makes a set with no zeros and return the minimum value in that set. Though it is worth pointing out this makes 2 iterations and is thus slower than Maor Refaeli's solution.
Upvotes: 0
Reputation: 164643
You can use the fact 0
is considered False
to filter out 0
values. Then use next
with a generator expression:
d = {1:0, 2:1, 3:2}
val = min(filter(None, d.values()))
res = next(k for k, v in d.items() if v == val) # 2
This will only return one key in the case of duplicate keys with 1
as value. For multiple matches, you can use a list comprehension:
res = [k for k, v in d.items() if v == val]
Note your literal ask for "minimum non-zero" will include negative values.
Performance note
The above solution is 2-pass but has time complexity O(n), it's not possible to have lower complexity than this. A 1-pass O(n) solution is possible as shown by @Maor, but this isn't necessarily more efficient:
# Python 3.6.0
%timeit jpp(d) # 43.9 ms per loop
%timeit mao(d) # 98.8 ms per loop
%timeit jon(d) # 183 ms per loop
%timeit reu(d) # 303 ms per loop
Code used for benchmarking:
from random import randint
n = 10**6
d = {i: randint(0, 9) for i in range(n)}
def jpp(d):
val = min(filter(None, d.values()))
return next(k for k, v in d.items() if v == val)
def mao(d):
min_val = None
result = None
for k, v in d.items():
if v and (min_val is None or v < min_val):
min_val = v
result = k
return result
def jon(d):
return min({i for i in d if d[i] != 0})
def reu(d):
no_zeros = {k: v for k, v in d.items() if v != 0}
key, val = min(no_zeros.items(), key=itemgetter(1))
return key
Upvotes: 4
Reputation: 2517
You can do it on one iteration.
d = {1:0, 2:1, 3:2}
# Save the minimum value and the key that belongs to it as we go
min_val = None
result = None
for k, v in d.items():
if v and (min_val is None or v < min_val):
min_val = v
result = k
print(result)
Some assumptions:
min_val
will hold the minimum valueUpvotes: 6
Reputation: 31339
Assuming the dict
is named a
:
from operator import itemgetter
a = {1:0, 2:1, 3:2}
# remove zeros
no_zeros = {k: v for k, v in a.items() if v != 0} # can use `if v`
# find minimal key and value (by value)
key, val = min(no_zeros.items(), key=itemgetter(1))
# key = 2, val = 1
Upvotes: 2