Search code examples
arraystwig

Dynamic multidimensional array in twig


I have an array, but I need to restructure it. I can only do this in twig.

Original array element looks like $arr[0]:

"_id" => array:3 [
"cityName" => "someCityName"
"id" => 111
"className" => "someClassName"
  ]
"count" => 85

my result array element should look like $arr[0]:

"someCityName" => [
    12 => [
        "someClassName" => 32,
        "someOtherClassName" => 44
    ]
]

in php I would just do

$arr[$cityName][$id][$className] = $count;

And this would work, but this must be done in twig.

I was hoping to use twig merge, but when I try doing

{% for infoArr in result %}
   {% set cityName = infoArr['_id']['cityName'] %}
   {% set id = infoArr['_id']['id'] %}
   {% set class = infoArr['_id']['className'] %}
   {% set countCity.cityName = countCity.cityName|merge({(id):([])}) %}
{% endfor %}

or

{% set countCity[cityName] = countCity[cityName]|merge({(id):([])}) %}

the error is Unexpected token "punctuation" of value "[" ("end of statement block" expected)

.

How should this be done in twig correctly?


Solution

  • If you wanted to do something like this in twig, which I'm not encouraging, you need to reconstruct every part of the array. Also note you can't use merge with numeric indeces, otherwise the data will be appended, not overwritten. More information on this issue here

    $data = [
        'data' => [
            [
                '_id' => [
                    'cityName'  => 'foo',
                    'className' => 'alpha',
                    'id'        => 42,
                ],
                'count' => 40,
            ],
            [
                '_id' => [
                    'cityName'  => 'bar',
                    'className' => 'alpha',
                    'id'        => 55,
                ],
                'count' => 123,
            ],
            [
                '_id' => [
                    'cityName'  => 'foo',
                    'className' => 'beta',
                    'id'        => 42,
                ],
                'count' => 99,
            ],
        ],
    ];
    

    {% set output = {} %}
    
    {% for raw in data %}
        {% if not attribute(output, raw._id.cityName) is defined %}
            {% set output = output|merge({ (raw._id.cityName) : {}, }) %}
        {% endif %}
    
        {% if not attribute(output[raw._id.cityName], 'id_'~raw._id.id) is defined %}
            {% set output = output|merge({(raw._id.cityName) : output[raw._id.cityName] | merge({('id_'~raw._id.id):[], }) }) %}
        {% endif %}
    
        {% set output = output|merge({(raw._id.cityName) : output[raw._id.cityName] | merge({('id_'~raw._id.id): output[raw._id.cityName]['id_'~raw._id.id]|merge({(raw._id.className): raw.count}), }) }) %}
    {% endfor %}
    
    
    {{ output.foo.id_42.alpha }} {# output: 40 #}
    

    demo