-1

Say I have the following list of dicts:

dicts = [
    {'name': "Tom", 'age': 20, 'height': 1.8},
    {'name': "Isa", 'age': 31, 'height': 1.5},
    ... ]

I'd like to replace the age of a given person with a given value.

def replace_age(person, age):
    dicts[?]['age'] = age

replace_age("Tom", 45)

Assuming that name is unique, what's the most elegant way to go about this?


In a golden world: dicts[name=person]['age'] = age


Not a duplicate of Find the index of a dict within a list, by matching the dict's value: I'm looking to change the value, not get the index. And Tom is a pretty common name.

snazzybouche
  • 2,241
  • 3
  • 21
  • 51
  • I want to change the value, not get the index. – snazzybouche Aug 20 '19 at 13:11
  • 2
    You first have to identify the proper dict in your list if you want to update it, that's the same as finding it's index. Also, your last remark 'Tom is a pretty common name' makes me wonder what you would want to do if there are many Toms in your list. That makes your question unclear... – Thierry Lathuille Aug 20 '19 at 13:28
  • 1
    @snazzybouche it's the critical part of your question. changing the value for a particular dictionary key is trivial and part of the Python language. Finding the right dictionary is covered by the duplicated question. I like code golf as much as the next person but it's not going to help you any more than the dupe will (though I admit I am always fond of the crazy one-liners people come up with) –  Aug 20 '19 at 13:35
  • @ThierryLathuille For the purposes of this question I have asserted that `name` is unique – snazzybouche Aug 20 '19 at 13:36

3 Answers3

3

this is a variant:

def replace_age(person, age):
    try:
        dct = next(item for item in dicts if item["name"] == person)
    except StopIteration:
        # person not found
        # here you could print a message or raise an error...
        return
    dct["age"] = age

this will only work if the names are unique. if they are not only the first occurrence will be replaced.

hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
  • 1
    the dictionary is changed in-place. for these functions it is conventional to return None. i have no idea what the OP needs if the person is not found in the dict... – hiro protagonist Aug 20 '19 at 13:04
  • 1
    I agree with hiro, it's better to pass None as second argument in next function. – Arsal Aug 20 '19 at 13:07
1

Here's my version

dictionaries = [
    {'name': "Tom", 'age': 20, 'height': 1.8},
    {'name': "Isa", 'age': 31, 'height': 1.5}
    ]

def change_dict_person_age(dictionaries, person, age):
    for dictionary in dictionaries:
        if dictionary['name'] == person:
            dictionary['age'] = age
            # Uncomment the following line if you want to stop at the 1st
            # match. Leave it as is if you want to modify all occurrences.
            #break

change_dict_person_age(dictionaries, "Tom", 40)
print(dictionaries)
#[{'name': 'Tom', 'age': 40, 'height': 1.8}, {'name': 'Isa', 'age': 31, 'height': 1.5}]

I also wrote a more generic version for broader user:

dictionaries = [
    {'name': "Tom", 'age': 20, 'height': 1.8},
    {'name': "Isa", 'age': 31, 'height': 1.5}
    ]

def change_dict(dictionaries, key_to_check, value_to_match, key_to_change, value_to_change):
    for dictionary in dictionaries:
        if dictionary[key_to_check] == value_to_match:
            dictionary[key_to_change] = value_to_change
            # Uncomment the following line if you want to stop at the 1st
            # match. Leave it as is if you want to modify all occurrences.
            #break

change_dict(dictionaries, "name", "Tom", "age", 50)
print(dictionaries)
#[{'name': 'Tom', 'age': 50, 'height': 1.8}, {'name': 'Isa', 'age': 31, 'height': 1.5}]
Pitto
  • 8,229
  • 3
  • 42
  • 51
1

since the name is unique you can change your data structure where you keep your data to achieve your task efficiently:

efficient_dict = {e['name']: {'age' : e.get('age'), 'height': e.get('height')} for e in dicts}

def replace_age(person, age):
    if person in efficient_dict:
        efficient_dict[person]['age'] = age
kederrac
  • 16,819
  • 6
  • 32
  • 55