Overwrite value in object in array I'm strangely having trouble with this simple Twig merge problem and can't find anything online. Simplified, let's say you had:

{% set users = [
    {name: 'Bill', age: 25},
    {name: 'Tim', age: 30},
    {name: 'John', age: 32}
] %}


How would you change, for example, Tim's age from 30 to 31?  I've tried:

{% set users = users[1]|merge({age: 31}) %}
{{ users[1].name }}: {{ users[1].age }}


But this doesn't work.
Solution

This won't work in Twig as presented in the question (see why below). Instead, users would need to be changed to an associative array (or "hash" in Twig terminology) with keys that aren't integers, and you'd have to insert a merge inside a merge to change the value:

{% set users = {
    person0: {name: 'Bill', age: 25},
    person1: {name: 'Tim', age: 30},
    person2: {name: 'John', age: 32}
} %}

{% set users = users|merge({ person1: users.person1|merge({age: 1000}) }) %}

{% for key, user in users %}
    {{ key }}: {{ user.name }}, {{ user.age }}&lt;br&gt;
{% endfor %}


...which now outputs:

person0: Bill, 25
person1: Tim, 1000
person2: John, 32


If you need to change the keys' integers dynamically, you will write it like this using Twig's attribute function and using brackets:

{% set loopIndex = 1 %}
{% set users = users|merge({ ('person' ~ loopIndex): attribute(users, 'person' ~ loopIndex)|merge({age: 1000}) }) %}




The Reason Why the Question's Array Doesn't Work

Twig's merge filter uses PHP's array_merge function, and according to PHP's docs when using array_merge:


  If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.


So trying to overwrite an existing hash in the original array

{% set users = [
    {name: 'Bill', age: 25},
    {name: 'Tim', age: 30},
    {name: 'John', age: 32}
] %} 


...will just add the hash as a new, fourth item in the array, not replace the second one.  To demonstrate this clearer, we can rewrite users as a hash like this (it's considered the same as above):

{% set users = {
    0: {name: 'Bill', age: 25},
    1: {name: 'Tim', age: 30},
    2: {name: 'John', age: 32}
} %}


By trying to target the key 1 to change its hash and output users:

{% set users = users|merge([ users.1|merge({age: 1000}) ]) %}

{% for key, user in users %}
    {{ key }}: {{ user.name }}, {{ user.age }}&lt;br&gt;
{% endfor %}


...we get this list:

0: Bill, 25
1: Tim, 30
2: John, 32
3: Tim, 1000


A new "Tim" user will get appended even if you make the keys strings like '0', '1', etc, or using Twig's attribute function. An issue for this was posted in Twig's github and the conversation explains it some more. You can only change a value if it's an array with a list of single values (not a hash) or if it's a key/value hash, and the key can't be an integer.