Reputation: 805
I have a value
value = 0.04532
Also, a dictionary similar to this
{'1': 0.02827, '2': 0.0, '3': 0.09827, '4': 0.04533}
I want to simply return the key of the value in the dictionary that is closest to my original value, 4
in this case
I found an older post that does something like this
newValue = value
answer = min(dict.items(), key=lambda (_, value): abs(value - newValue))
This returns the tuple ('4', 0.04533)
and I just want the key (as an int).
Furthermore, I'm having trouble understanding what that code is doing exactly.
Is there a cleaner way to get this done?
Upvotes: 12
Views: 10312
Reputation: 164773
You can use sequence unpacking to unpack your tuple
result:
value = 0.04532
d = {'1': 0.02827, '2': 0.0, '3': 0.09827, '4': 0.04533}
res_key, res_val = min(d.items(), key=lambda x: abs(value - x[1]))
print(res_key, res_val, sep=', ')
4, 0.04533
Half the problem appears to be in your choice of variables. Make sure you don't shadow class names, e.g. call your dictionary d
, not dict
. Likewise, don't name an argument of your lambda
the same as a variable you've already defined.
Otherwise, the logic via min
works as follows:
d.items
, i.e. key-value pairs.lambda x: abs(value - x[1])
to each tuple, i.e. calculate the absolute difference versus value
.lambda
function and return the argument supplied, in this case a single tuple
from d.items
.Note PEP 3113 removes tuple parameter unpacking from Python 3.x, which is why we must explicitly extract the first value via x[1]
in our lambda
.
Upvotes: 10
Reputation: 78750
dict.items
gives you the (key, value) pairs of the dictionary.
>>> d = {'1': 0.02827, '2': 0.0, '3': 0.09827, '4': 0.04533}
>>> d.items()
dict_items([('1', 0.02827), ('3', 0.09827), ('2', 0.0), ('4', 0.04533)])
The return value is iterable and therefore can be passed to min
.
min
also takes a keyword argument key
which has to be a callable (usually a function). It is the criterion by which min
evaluates the elements from its first argument in order to find the minimum.
Here is a much simpler example. Suppose we need to find the shortest list within a list of lists.
>>> lists = [[1, 2], [1, 2, 3], [5]]
>>> min(lists, key=len)
[5]
min
iterates over lists
, calls len(sublist)
for every sublist
in lists
and returns the element where len(sublist)
was minimal.
Examining, the proposed solution,
lambda (_, value): abs(value - newValue)
is an (anonymous) function (using Tuple Parameter Unpacking which no longer works in Python 3) supposed to take an item, a (key, value) pair, and return abs(value - newValue)
, which measures how close value
is to newValue
.
If the lambda
confuses you, here's how you would write that key
function in Python 3 as a normal function.
>>> def criterion(dict_item):
... key, value = dict_item # unpack
... return abs(value - newValue)
You can now issue
>>> newValue = 0.04532
>>> d = {'1': 0.02827, '2': 0.0, '3': 0.09827, '4': 0.04533}
>>>
>>> min(d.items(), key=criterion)
('4', 0.04533)
If you want just the key as an integer, get it from index 0
and turn it into an int
.
>>> int(min(d.items(), key=criterion)[0])
4
Finally, don't use the variable name dict
, that name should be reserved for the builtin dictionary type.
Upvotes: 4
Reputation: 1350
That code you referenced is simply looping through the key value pairs in the dictionary, computing the differences with your expected value and returning the minimum key value pair.
To just obtain the value, you can simply do this:
answer = min(dict.items(), key=lambda (_, value): abs(value - newValue))[1]
Are you sure you want it as an int type, it'll round down to the nearest integer
I would suggest just wrapping the statement above with a float()
Upvotes: 3