Modify dict values inplace
28,064
Solution 1
You may find multiply is still faster than dividing
d2 = {k: v * 0.5 for k, v in d.items()}
For an inplace version
d.update((k, v * 0.5) for k,v in d.items())
For the general case
def f(x)
"""Divide the parameter by 2"""
return x / 2.0
d2 = {k: f(v) for k, v in d.items()}
Solution 2
You can loop through the keys and update them:
for key, value in d.items():
d[key] = value / 2
Solution 3
Should work for you:
>>> d = {'a':2.0, 'b':3.0}
>>> for x in d:
... d[x]/=2
...
>>> d
{'a': 1.0, 'b': 1.5}
Solution 4
>>> d = { 'a': 2, 'b': 3 }
>>> {k: v / 2.0 for k, v in d.items()}
{'a': 1.0, 'b': 1.5}
Author by
Qortex
Creating a startup (Qontrol) to help companies manage their cybersecurity risk with a dynamic and easy-to-use SaaS.
Updated on July 09, 2022Comments
-
Qortex almost 2 years
I would like to apply a function to values of a
dict
inplace in thedict
(likemap
in a functional programming setting).Let's say I have this
dict
:d = { 'a':2, 'b':3 }
I want to apply the function
divide by 2.0
to all values of the dict, leading to:d = { 'a':1., 'b':1.5 }
What is the simplest way to do that?
I use Python 3.
Edit: A one-liner would be nice. The
divide by 2
is just an example, I need the function to be a parameter. -
Qortex about 11 yearsThis creates a new dictionary right? So with a huge
dict
, it would be resource intensive. Is there a way to just modify the values without losing the advantage of having the already builtdict
? (hence theinplace
in my question) -
Admin about 11 years@Mic Don't worry about performance unless there is a performance problem (and I'm not saying there isn't, but justify the assertion) - or keeping the same object is required for other semantic reasons. That being said, I entirely agree with jamylak - "inplace" (mutating) and "functional" (immutable) are fairly orthogonal, depending on where the line is drawn.
-
jamylak about 11 years@Mic True but when I heard the word 'functional' I didn't think you would tell me this.
-
mgilson about 11 yearsThis'll work in python2.7 also other than maybe doing integer division sometimes (which is easily fixed with a judiciously placed period).
-
mgilson about 11 yearsNote that you could also do
d.update((k,v/2.) for k,v in d.items())
if you wanted it in-place. -
jamylak about 11 years@mgilson You can submit that if you want, I don't really like it that much
-
Jonathan Vanasco about 11 yearsYou should also note in the answer that this creates a new list , and there is little reason not to create a new list. This is what I would do , but this doesn't answer the actual question.
-
jamylak about 11 years@JonathanVanasco There are no new lists being created
-
abarnert about 11 years@mgilson: I think
d.update({k: v/2.0 for k, v in d.items()})
is more readable (and more obviously related to jamylak's answer). -
Jonathan Vanasco about 11 yearssorry, i meant dict. your answer creates a new one and leaves the original one intact.
-
Jonathan Vanasco about 11 yearsand now the question has been edited so there is a d2, not the origina
d
. so nevermind, though the question title should be changed. -
mgilson about 11 years@abarnert -- Yes, but I thought that OP was trying to save memory for one reason or another...
-
abarnert about 11 yearsYou really think multiplying will be significantly faster than dividing? Maybe in PyPy, where all of the costs but the arithmetic are shrunk down to the point where it makes a difference, but in CPython, I'll bet you can't even detect the difference…
-
jamylak about 11 years@abarnert Then you would be creating a new dictionary so you may as well use my method... mgilson's one has the benefit of using a generator
-
abarnert about 11 yearsAlso, I think passing the dict comprehension to
d2
instead of a generator expression generating tuples may be more readable in this case (even if it does "wastefully" create a new dictionary). -
mgilson about 11 yearsAnyway, I don't really think I would use that. That's why I made it a comment rather than an answer. (I prefer the for loop).
-
mgilson about 11 yearsAs a side note, I don't actually like dict comprehensions in python3.x code for a two main reasons -- 1) Your code isn't backward compatible with python2.6, 2) dict comprehensions look just a little bit too similar to set comprehensions. (I also don't really like set literals for the same reason)
-
abarnert about 11 years
%timeit
results. CPython 2.7.2: 1.11us vs. 1.12us, or 222us vs. 223us for a large (1000-item random) dictionary. CPython 3.3.0: 785ns vs. 778ns, or 160us vs. 158us. So, multiplying is not faster than dividing, as I suspected. (I haven't tested PyPy yet because I broke myipython-pypy
…) -
abarnert about 11 yearsOK, fixed… PyPy 1.9.0: 309ns vs. 329ns, or 94.4us vs. 94.8us. So, with PyPy, with tiny dictionaries, multiplying is slightly faster. With CPython, or with non-tiny dictionaries, they're equivalent.
-
abarnert about 11 years@mgilson: I love dict comprehensions. Set literals are a different story, but only because
{}
is not the empty set, which is about as big an irregularity as you can have in a set display format… -
abarnert about 11 years@mgilson: I agree. Paraphrasing Guido off python-ideas: If you want mutating code, write it explicit with for. If you must have it in one line, just put the body after the colon.
-
mgilson about 11 yearsThis could be a 1-liner as well (if you cheat a little) --
for key,value in d.items(): d[key] = value/2
-
abarnert about 11 yearsI don't think explicitly using
items
andvalue
in this case is saving anything in readability (or performance, if that matters); Ishpeck's answer looks simpler (except for your better variable name). -
abarnert about 11 years@mgilson: If Guido suggests it, it doesn't count as cheating, right? (Of course he suggests it as "If you must have it on one line…")
-
mgilson about 11 years@abarnert -- Apparently guido also once tweeted that you can use triple-quoted strings as a block comment ... Apparently I don't agree with him on everything
-
Qortex about 11 years@mgilson indeed, I can't have two copies of this dict or my VM basically dies. Hence the
inplace
in the title. -
John La Rooy about 11 years@abarnert, well I started by saying "You may find..." :)
-
abarnert about 11 years@Mic: Are you sure that's really a problem? And, if so, why did you tag this "functional-programming"?
-
abarnert about 11 years@mgilson: Of course not. But when he agrees with you, he's always right! That's the beauty of authority. :)
-
abarnert about 11 years@Mic: That's really kind of misleading, if you understand what
dict.update
does. You have to figure out that the generator expression is effectively generating a lazy dictionary with the exact same keys as the original before you realize that it's changing each value in-place, while withfor key in d: d[key] /= 2
it's immediately apparent what you're doing.