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.
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.
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 valueYou 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
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
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.
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