1

I have a list of dictionaries like below:

my_dict_1 = {'a': 1, 'b': 2, 'c': 3}
my_dict_2 = {'a': 10, 'b': 20, 'c': 30}

original_list = [my_dict_1, my_dict_2]

I am trying to iterate over this list and change one of the keys of the original dictionaries while keeping the order of the keys the same as the original. So the resulting dictionaries will be like this:

 my_dict_1 = {'a': 1, 'New': 2, 'c': 3}
 my_dict_2 = {'a': 10, 'New': 20, 'c': 30}

Can it be done in a single for loop ? So far tried this:

for i in [my_dict_1, my_dict_2]:
    i['NEW'] = i.pop('b')

print(my_dict_1)

output: {'a': 1, 'c': 3, 'NEW': 2}

The result does not keep the original order.

Imran
  • 71
  • 5
  • Dupe of [Rename a dictionary key](https://stackoverflow.com/q/16475384/674039)? – wim Apr 17 '23 at 21:58

1 Answers1

3

Can it be done in a single for loop?

No.

Since python dictionaries (>=3.7) preserve insertion order, your best option may just be to re-create the dictionaries, taking care to replace the old key with the new when it comes up.

Here's an example:

new_list = [
  {(k if k != 'b' else 'NEW') : v for k, v in d.items()} for d in original_list
]
print (new_list) 
# [{'a': 1, 'NEW': 2, 'c': 3}, {'a': 10, 'NEW': 20, 'c': 30}]

If you have several replacements needed, here's a suggestion to maintain a replacement dict and call it inside your comprehension:

replace = {'b': 'NEW', ...}
new_list = [
   { replace.get(k, k) : v for k, v in d.items() } for d in original_list
]    
print (new_list) 
# [{'a': 1, 'NEW': 2, 'c': 3}, {'a': 10, 'NEW': 20, 'c': 30}]

The loopy way to do this would be

new_list = []
for d in original_list:
    new_list.append({replace.get(k, k) : v for k, v in d.items()})

print (new_list)
# [{'a': 1, 'NEW': 2, 'c': 3}, {'a': 10, 'NEW': 20, 'c': 30}]

If you want to create a readability nightmare (not recommended), here's a functional approach courtesy @Kelly Bundy

new_list = list(map(
             lambda d: dict(zip(map(replace.get, d, d), d.values())), 
             original_list))
print (new_list)
# [{'a': 1, 'NEW': 2, 'c': 3}, {'a': 10, 'NEW': 20, 'c': 30}]
cs95
  • 379,657
  • 97
  • 704
  • 746
  • Just another variation: `dict(zip(map(replace.get, d, d), d.values()))` – Kelly Bundy Apr 17 '23 at 21:59
  • @KellyBundy functional programming ftw! thanks for the suggestion – cs95 Apr 17 '23 at 22:04
  • Ha, I didn't mean in a silly `list(map(lambda` but in a list comp :-). And that's not a readability nightmare. Give me a minute... – Kelly Bundy Apr 17 '23 at 22:21
  • 1
    There you go: `new_list = list(map(dict, map(zip, map(map, itertools.repeat(replace.get), original_list, original_list), map(dict.values, original_list))))`. [Demo](https://ato.pxeger.com/run?1=XZCxCsIwFEVxzVdkSwu11LqI4ujq6iBSYo0aSJuQvipV-iUuLvpRfo2vtqloINwXuPfwcm9PU8FR5_f7o4T9cPIazGRmtAUqQVjQWhUkq5KdTCEZ0Tm9Ms6mdBRQtkWNUVPUcd2b4q8pcq7I2aKaaCsPMucqUbIA9K57ekB7xoYQK4ziqfjQGghbLlasJiQXZxdtxMu48ZoQpnG6SNMOeIPvF0KkCQ5eBw0PAvyA_qzy9_RbTEMOT1yVovg34CHEWJmD53by2w67Kl2lbw). – Kelly Bundy Apr 17 '23 at 22:28