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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With