Reputation: 13
I have a list of dictionaries. Each dictionary in the list has the same keys but each has different values, e.g.:
my_list = [
{key1: 100, key2: 110, key3: 120},
{key1: 200, key2: 210, key3: 220},
{key1: 300, key2: 310, key3: 320}]
I used the following to replace key2
with a new key new_key2
:
list(map(lambda x: x.update({"new_key2": x.pop("key2")}), my_list))
The code works and my_list
is updated correctly, but I cannot understand the following behavior:
my_list = list(map(lambda x: x.update({"new_key2" : x.pop ("key2")}), my_list))
In this case my_list
returned the following values:
my_list[0] = None
my_list[1] = None
my_list[2] = None
Why? Shouldn't 'list + map' functions retrieve me a list?
Upvotes: 1
Views: 494
Reputation: 109636
The result of an update
statement is None
, hence why the returned result is [None, None, None]
. There is no need to call list
on the map
function. This function is updating each item in mylist
inplace.
I believe the following code is more pythonic and also handles the case when there is no key2
. The variable mylist
is modified inplace, so there is no need to reassign it to a list. The approach below is slightly more memory efficient compared to a reassigning the result of a list comprehension.
for d in mylist:
try:
d['new_key2'] = d.pop('key2')
except KeyError:
pass # no 'key2'
>>> mylist
[{'key1': 100, 'key3': 120, 'new_key2': 110},
{'key1': 200, 'key3': 220, 'new_key2': 210},
{'key1': 300, 'key3': 320, 'new_key2': 310}]
If you prefer to use the map
method (it is faster in this case), I'd recommend the following:
map(lambda x:
x.update({"new_key2": x.pop("key2")})
if 'key2' in x else None, mylist)
There is no need to assign the result, as it is just a list of None values.
Upvotes: 2
Reputation: 61032
So there are two ways to do this. The first modifies the existing dictionaries (and returns a reference to the dictionary so you don't have to deal with None
)
def replace_key(old_key, new_key, d):
d[new_key] = d.pop('old_key')
return d
mylist = [replace_key('key2', 'newkey2', d) for d in mylist]
The second is a more pure functional approach without side effects (I wouldn't recommend this for real applications, it's much less efficent)
mylist = [{k : v if k != 'key2' else 'newkey2': v for k, v in d.items()} for d in mylist]
Upvotes: 0
Reputation: 1958
Your lambda function does not return anything, it just updates the list. Look at this block of code.
In [15]: mylist = [
{'key1' : 100, 'key2' : 110, 'key3' : 120},
{'key1' : 200, 'key2' : 210, 'key3' : 220},
{'key1' : 300, 'key2' : 310, 'key3' : 320}]
In [16]: list(map(lambda x: x.update({"mewkey2" : x.pop ("key2")}), mylist))
Out[16]: [None, None, None]
In [17]: mylist
Out[17]:
[{'key1': 100, 'key3': 120, 'mewkey2': 110},
{'key1': 200, 'key3': 220, 'mewkey2': 210},
{'key1': 300, 'key3': 320, 'mewkey2': 310}]
If you want to have a new variable corresponding to this new list, do something like
newlist = mylist[::]
list(map(lambda x: x.update({"mewkey2" : x.pop ("key2")}), newlist))
Upvotes: 2