41
my_dicts = [ 
    { 'key1' : 'value1',
      'key2' : 'value2' },

    { 'key1' : 'value1',  
      'key2' : 'value2' },

    { 'key1' : 'value1',  
      'key2' : 'value2' }]

What would be the most efficient way to replace all instances of 'value2' with 'value3' ?

Braiam
  • 1
  • 11
  • 47
  • 78
dave
  • 7,717
  • 19
  • 68
  • 100
  • Are looking for 'value2' within varying 'keyX'? How many updates will you be performing, just one per traversal? – kevpie Nov 27 '10 at 12:23
  • 1
    What assumptions can be made -- like will it always be associated with the same key, or can it occur under other or multiple keys? Will you ever want to update more than one value at a time? – martineau Nov 27 '10 at 12:31

4 Answers4

63

I did not do any timings, but you probably can't get much better than

for d in my_dicts:
    d.update((k, "value3") for k, v in d.iteritems() if v == "value2")

Update for Python3

for d in my_dicts:
    d.update((k, "value3") for k, v in d.items() if v == "value2")
Mathieu Dhondt
  • 8,405
  • 5
  • 37
  • 58
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
13

Python3.7 dict comprehension (will return a deep copy though):

update = {'key2':'value3'}
new_dicts = [{**d,**update} for d in my_dicts]
aaa90210
  • 11,295
  • 13
  • 51
  • 88
  • 1
    Wow, such a cool one-liner. Love this solution. Just a tweak to this code and you can pass a function to do some processing. ```plans = [{**plan, "description": plan.get("description").split(";")} for plan in plans]``` – akilesh raj Dec 26 '22 at 07:25
4
for x in my_dicts:
    for y in x:
        if x.get(y) == 'value2':
            x.update({y: "value3"})
Brent
  • 49
  • 1
  • 12
    Include an explanation of your solution rather than just the code. This will help the OP understand the solution. – Tim Jan 22 '20 at 13:47
3

Here's a very general answer designed to handle multiple occurrences of multiple values in large dictionaries. Handling simpler more specific cases and/or with small dictionaries -- like your example -- could be done significantly faster.

from collections import defaultdict

my_dicts = [
    { 'key1' : 'value1',
      'key2' : 'value2' },

    { 'key1' : 'value1',
      'key2' : 'value2',
      'key3' : 'value2'  }, # dup added for testing

    { 'key1' : 'value1',
      'key2' : 'value2' }]

def reverse(dct):
    """ Create dictionary mapping each value to list of one or more keys """
    ret = defaultdict(list)
    for key,val in dct.iteritems():
        ret[val].append(key)
    return ret

def replace_values(dicts, replacments):
    """ Replace values in each dict in dicts """
    for dct in dicts:
        revdict = reverse(dct)
        for oldval,newval in replacments.iteritems():
            for key in revdict.get(oldval, []):
                dct[key] = newval

replace_values(my_dicts, {'value2':'value3'})
print my_dicts
# [{'key2': 'value3', 'key1': 'value1'},
#  {'key3': 'value3', 'key2': 'value3', 'key1': 'value1'},
#  {'key2': 'value3', 'key1': 'value1'}]
martineau
  • 119,623
  • 25
  • 170
  • 301