afjm
afjm

Reputation: 179

Group elements from an array with a new element containing group value

I have an array like this one:

$array = [
     ['Categoria' => 'example', 'Servico' => 'name1'],
     ['Categoria' => 'example', 'Servico' => 'name2'],
     ['Categoria' => 'example', 'Servico' => 'name3'],
     ['Categoria' => 'example2', 'Servico' => 'name4'],
     ['Categoria' => 'example2', 'Servico' => 'name5'],
     ['Categoria' => 'example2', 'Servico' => 'name6'],
     ['Categoria' => 'example3', 'Servico' => 'name7'],
     ['Categoria' => 'example3', 'Servico' => 'name8'],
     ['Categoria' => 'example3', 'Servico' => 'name9']
];

I need to transform this on something like:

[
    [
        'Servico' => 'example',
        'children' => [
            ['Servico' => 'name1'],
            ['Servico' => 'name2'],
            ['Servico' => 'name3'],
        ]
    ],
    [
        'Servico' => 'example2',
        'children' => [
            ['Servico' => 'name4'],
            ['Servico' => 'name5'],
            ['Servico' => 'name6'],
        ]
    ],
    [
        'Servico' => 'example3',
        'children' => [
            ['Servico' => 'name7'],
            ['Servico' => 'name8'],
            ['Servico' => 'name9'],
        ]
    ],
]

I have read this topic and I successfully have grouped my array, but I couldn't find a way to format the array in a way I have Servico and children on each object.

Someone have any ideas?

Upvotes: 1

Views: 74

Answers (3)

mickmackusa
mickmackusa

Reputation: 48000

There is no need for multiple loops or conditions or counters here.

Every group's Servico value ($row['Categoria']) can be safely overwritten on each iteration.

Each new $row['Servico'] value is to be unconditionally pushed into the respective children subarray.

After using $row['Categoria'] to provide temporary grouping keys in the result array, re-index the result with array_values().

*Note: I am electing to flatten the data structure of children to be an indexed array. I don't see any value in creating single-element associative arrays for each entry. If you DO want that then push ['Servico' => $row['Servico']] into the children.

Functional-style with array_reduce(): (Demo)

var_export(
    array_values(
        array_reduce(
            $array,
            function ($carry, $row) {
                $carry[$row['Categoria']]['Servico'] = $row['Categoria'];
                $carry[$row['Categoria']]['children'][] = $row['Servico'];
                return $carry;
            }
        )
    )
);

Classic foreach(): (Demo)

$result = [];
foreach ($array as $row) {
    $result[$row['Categoria']]['Servico'] = $row['Categoria'];
    $result[$row['Categoria']]['children'][] = $row['Servico'];
}
var_export(array_values($result));

Upvotes: 1

romal tandel
romal tandel

Reputation: 501

just assume $array is your array

$i=0;
$temp = array();
foreach ($array as $arr)
{
    if($i !=0 && $arr['Categoria'] == $temp[$i-1]['Servico']){
        $temp[$i-1]['children']['Servico'] = $arr['Servico'];
    }else{
        $temp[$i]['Servico'] =$arr['Categoria'];
        $temp[$i]['children']['Servico'] = $arr['Servico'];
        $i++;
    }
}
//$temp is your new array

Upvotes: 0

Andreas
Andreas

Reputation: 23968

You can foreach the array and build a new array with the structure you want.

$new =array();
Foreach($A as $item){
    If(!isset($new[$item['Categoria']])) $new[$item['Categoria']] = array(); // create array of not set
    $new[$item['Categoria']][] = $item['Servico']; // add servico item to array
}

This loops each item if it does not find the subarray it will create it.
Then add the 'name' values in the subarray.

Edit, see now that you want your output array to be named B, just change 'new' to 'B' in the code.

Upvotes: 0

Related Questions