<p>This could also be accomplished with the <a href="https://twig.symfony.com/doc/2.x/filters/map.html" rel="noreferrer">map</a> filter, if you’re running Craft 3.1.29 or later:</p>
<pre><code>{% set users = [
    {name: 'Bill', age: 25},
    {name: 'Tim', age: 30},
    {name: 'John', age: 32}
] %}

{% set users = users|map(u =&gt; u.name == 'Tim' ? u|merge({age: 31}) : u) %}
</code></pre>

CC BY-SA 4.0
2022-10-20T13:59:23.420Z
I like this solution. Thank you!
Mark Notton
CC BY-SA 4.0
2020-10-07T13:52:43.943Z
2020-10-07T13:52:43.943Z
Brandon Kelly
<p>A little bit nasty but you could do it like this (I could not find anything else)<br>
Create this function in your plugins Variable</p>

<pre><code>/**
 * @param array $array The array to modify
 * @param string $path The path in the array
 * @param mixed $value The value to set
 * @param string $delimiter The separator for the path
 * @return The new array
 */
function setNestedArrayValue($array, $path, $value, $delimiter = '/') {
    $pathParts = explode($delimiter, $path);

    $current = &amp;$array;
    foreach($pathParts as $key) {
        $current = &amp;$current[$key];
    }
    $current = $value;

    return $array;
}
</code></pre>

<p>Then you have this in your twig template</p>

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

{% set users = craft.pluginHandle.setNestedArrayValue(users, '0/age', 40) %}
</code></pre>

CC BY-SA 3.0
2017-10-27T21:17:42.093Z
I was hoping to do this in Twig.  If the answer is that it can't be done in Twig, that would be good to have documented somewhere, and I could accept that as the answer. Maybe an alternative Twig array setup would be nice to see, even if it means sacrificing some flexibility in my example.  I think a plugin is a bit overkill.
Ryan
CC BY-SA 3.0
2017-10-27T21:21:19.337Z
Why overkill? It takes only about 1 min to create the plugin. Don't get me wrong, I don't want to defend my answer or something, I just don't understand why so many people refuse to use a plugin in craft. A plugin doesn't even make your code noticeable slower.
Robin Schambach
CC BY-SA 3.0
2017-10-29T18:24:43.277Z
Well although a plugin is a solution, it's not really the answer to the question. And although I understand that Twig was not meant for heavy logic, sometimes you just need to change a value in a custom associative array like this and I don't want to add another plugin to the group just to do a simple task if I can help it.  If this were a part of a greater chunk of logic, then sure, write a plugin and do it in php.
Ryan
CC BY-SA 3.0
2017-10-29T18:26:55.390Z
Well then you can't solve your problem. It's not intended to do such things in twig. So the answer is: you can't do it in twig alone
Robin Schambach
CC BY-SA 3.0
2017-10-29T21:53:58.720Z
I think you can do this in Twig, but you have to adjust the `users` array to be a hash. A dynamic solution is presented in my answer I posted.
Ryan
CC BY-SA 3.0
2017-10-27T20:05:55.320Z
2017-10-27T20:57:48.380Z
2017-10-27T20:57:48.380Z
Robin Schambach
<p>Did you try something like:</p>

<pre><code>{% set users[1]['age'] = 31 %}
</code></pre>

CC BY-SA 3.0
2017-10-29T21:49:09.210Z
No, this results in an error saying `Unexpected token "punctuation" of value "[" ("end of statement block" expected).` Twig makes you use its `merge` filter to change values in an array or hash (associative array).
Ryan
CC BY-SA 3.0
2017-10-28T21:58:57.427Z
2017-10-28T21:58:57.427Z
Jim Wyse
<h3>Solution</h3>

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

<pre><code>{% 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 %}
</code></pre>

<p>...which now outputs:</p>

<pre><code>person0: Bill, 25
person1: Tim, 1000
person2: John, 32
</code></pre>

<p>If you need to change the keys' integers dynamically, you will write it like this using Twig's <a href="https://twig.symfony.com/doc/2.x/functions/attribute.html" rel="noreferrer"><code>attribute</code></a> function and using brackets:</p>

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

<hr>

<h3>The Reason Why the Question's Array Doesn't Work</h3>

<p>Twig's <code>merge</code> filter uses PHP's <code>array_merge</code> function, and according to PHP's docs when using <a href="http://php.net/manual/en/function.array-merge.php" rel="noreferrer"><code>array_merge</code></a>:</p>

<blockquote>
  <p>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, <strong>but will be appended</strong>.</p>
</blockquote>

<p>So trying to overwrite an existing hash in the original array</p>

<pre><code>{% set users = [
    {name: 'Bill', age: 25},
    {name: 'Tim', age: 30},
    {name: 'John', age: 32}
] %} 
</code></pre>

<p>...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 <code>users</code> as a hash like this (it's considered the same as above):</p>

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

<p>By trying to target the key <code>1</code> to change its hash and output <code>users</code>:</p>

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

{% for key, user in users %}
    {{ key }}: {{ user.name }}, {{ user.age }}&lt;br&gt;
{% endfor %}
</code></pre>

<p>...we get this list:</p>

<pre><code>0: Bill, 25
1: Tim, 30
2: John, 32
3: Tim, 1000
</code></pre>

<p>A new "Tim" user will get appended even if you make the keys strings like <code>'0'</code>, <code>'1'</code>, etc, or using Twig's <code>attribute</code> function. <a href="https://github.com/twigphp/Twig/issues/789" rel="noreferrer">An issue for this</a> 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.</p>

CC BY-SA 3.0
2017-10-29T21:46:41.510Z
2017-10-29T22:02:07.303Z
2017-10-29T22:02:07.303Z
Ryan
<p>I'm strangely having trouble with this simple Twig merge problem and can't find anything online. Simplified, let's say you had:</p>

<pre><code>{% set users = [
    {name: 'Bill', age: 25},
    {name: 'Tim', age: 30},
    {name: 'John', age: 32}
] %}
</code></pre>

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

<pre><code>{% set users = users[1]|merge({age: 31}) %}
{{ users[1].name }}: {{ users[1].age }}
</code></pre>

<p>But this doesn't work.</p>

<templating><array><merge>
Overwrite value in object in array
# Overwrite value in object in array

(Asked by: username_0 on 2017-10-27)

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.

**Tags:** templating, array, merge

---

## 4 answers

### Answer by username_0 on 2017-10-29. Score: 13 | Accepted answer

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 }}
{% 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 }}
{% 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.


---

### Answer by username_1 on 2020-10-07. Score: 5

This could also be accomplished with the map filter, if you’re running Craft 3.1.29 or later:
{% set users = [
    {name: 'Bill', age: 25},
    {name: 'Tim', age: 30},
    {name: 'John', age: 32}
] %}

{% set users = users|map(u => u.name == 'Tim' ? u|merge({age: 31}) : u) %}

> **Comments:**
> **username_2**: I like this solution. Thank you!  

---

### Answer by username_3 on 2017-10-27. Score: 0

A little bit nasty but you could do it like this (I could not find anything else)
Create this function in your plugins Variable
/**
 * @param array $array The array to modify
 * @param string $path The path in the array
 * @param mixed $value The value to set
 * @param string $delimiter The separator for the path
 * @return The new array
 */
function setNestedArrayValue($array, $path, $value, $delimiter = '/') {
    $pathParts = explode($delimiter, $path);

    $current = &$array;
    foreach($pathParts as $key) {
        $current = &$current[$key];
    }
    $current = $value;

    return $array;
}

Then you have this in your twig template
 {% set users = [
    {name: 'Bill', age: 25},
    {name: 'Tim', age: 30},
    {name: 'John', age: 32}
] %}

{% set users = craft.pluginHandle.setNestedArrayValue(users, '0/age', 40) %}

> **Comments:**
> **username_0**: I was hoping to do this in Twig.  If the answer is that it can't be done in Twig, that would be good to have documented somewhere, and I could accept that as the answer. Maybe an alternative Twig array setup would be nice to see, even if it means sacrificing some flexibility in my example.  I think a plugin is a bit overkill.  
> **username_3**: Why overkill? It takes only about 1 min to create the plugin. Don't get me wrong, I don't want to defend my answer or something, I just don't understand why so many people refuse to use a plugin in craft. A plugin doesn't even make your code noticeable slower.  
> **username_0**: Well although a plugin is a solution, it's not really the answer to the question. And although I understand that Twig was not meant for heavy logic, sometimes you just need to change a value in a custom associative array like this and I don't want to add another plugin to the group just to do a simple task if I can help it.  If this were a part of a greater chunk of logic, then sure, write a plugin and do it in php.  
> **username_3**: Well then you can't solve your problem. It's not intended to do such things in twig. So the answer is: you can't do it in twig alone  
> **username_0**: I think you can do this in Twig, but you have to adjust the `users` array to be a hash. A dynamic solution is presented in my answer I posted.  

---

### Answer by username_4 on 2017-10-28. Score: -1

Did you try something like:
{% set users[1]['age'] = 31 %}

> **Comments:**
> **username_0**: No, this results in an error saying `Unexpected token "punctuation" of value "[" ("end of statement block" expected).` Twig makes you use its `merge` filter to change values in an array or hash (associative array).  

---

