[Tutor] Manipulating Dictionary values
Steven D'Aprano
steve at pearwood.info
Mon Dec 26 06:09:02 EST 2016
On Mon, Dec 26, 2016 at 01:33:37PM +0530, Sunil Tech wrote:
> Hi Team,
>
> Dictionary is like
>
> a = {'a': 'New', 'b': 'Two', 'l': [{'k': 'test', 'm': 'again'}, {'k':
> 'test', 'm': 'again'}]}
>
> I am trying to modify a value in the dictionary value at a['l'] & at 'm'
> expecting it to be
>
> a = {'a': 'New', 'b': 'Two', 'l': [{'k': 'test', 'm': 'replaced'}, {'k':
> 'test', 'm': 'replaced'}]}
Simplify the problem. The dictionary "a" is not relevant. All the
processing is happening to the list:
[{'k': 'test', 'm': 'again'}, {'k': 'test', 'm': 'again'}]
First thing: don't use the string.replace() method unless that is what
you *really* mean. Remember that replace works on substrings, not the
entire string. Suppose you have:
[{'k': 'test', 'm': 'against'}, {'k': 'test', 'm': 'again'}]
If you use string.replace('again', 'replaced') then your result will be:
[{'k': 'test', 'm': 'replacedst'}, {'k': 'test', 'm': 'again'}]
which is surely not what you want.
So your first question should be: how do you change the value of a
dict with key 'm' from 'again' to 'replaced'?
# Before
d = {'a': 'something', 'b': 'who cares?', 'm': 'again'}
# After
d = {'a': 'something', 'b': 'who cares?', 'm': 'replaced'}
And the answer is:
if d['m'] == 'again':
d['m'] = 'replaced'
Now you just need to write a loop to do that for every dict in the list:
alist = [{'k': 'test', 'm': 'again'}, {'k': 'test', 'm': 'again'}]
for adict in alist:
if adict['m'] == 'again':
adict['m'] = 'replaced'
print(alist)
What if the list is inside a dict? It doesn't matter.
a = {'a': 'New',
'b': 'Two',
'l': [{'k': 'test', 'm': 'again'}, {'k': 'foo bar', 'm': 'again'}],
'z': 'something else',
}
for adict in a['l']:
if adict['m'] == 'again':
adict['m'] = 'replaced'
print(a)
Last one: can we do this as an expression, using a list comprehension?
(Why do we want to?) Yes, but only by writing more complicated code and
doing much more work, which means it will probably be slower. MUCH
slower.
a = {'a': 'New',
'b': 'Two',
'l': [{'k': 'test', 'm': 'again'}, {'k': 'foo bar', 'm': 'again'}],
'z': 'something else',
}
a['l'] = [**** for adict in a['l']]
What code goes into the **** in the list comp? It has to be a function
which takes a dict, and returns the same dict, or a copy of that dict,
with value associated with the key 'm' conditionally replaced.
(If this sounds complicated to you, that's because it is complicated.
Why does this have to be a list comprehension?)
I can easily write a helper function:
def modify(adict):
if adict['m'] == 'again':
adict['m'] = 'replaced'
return adict
and then use:
a['l'] = [modify(adict) for adict in a['l']]
but what if you don't want the helper function? Then it becomes really
complicated, but here is a one-liner with no dependencies and no helper
functions needed:
a['l'] = [dict([(key, 'replaced' if value is 'again' else value) for (key, value) in adict.items()]) for adict in a['l']]
Look how much unnecessary and pointless work this does, and how hard it
is to understand, compared to this version:
for adict in a['l']:
if adict['m'] == 'again':
adict['m'] = 'replaced'
One really complicated, hard to understand, slow line, versus three
simple, easy to understand, fast lines.
Beginners often want to do things as one-liners. More experienced coders
keep asking, why does it need to be a one-liner? How much extra work do
you want to do just to avoid pressing the Enter key on your keyboard?
--
Steve
More information about the Tutor
mailing list