1

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?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
afjm
  • 169
  • 12
  • 1
    Wait... How can you have several keys in the same array with the same name? – Andreas Nov 13 '17 at 12:21
  • @Andreas, I have a `faher` with **Servico** and all of its `children` also must have **Servico** as a key. I don't think this would be a problem. – afjm Nov 13 '17 at 12:24

3 Answers3

1

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));
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • this one is perfect! But I was playing with your code and I did something like [that](http://sandbox.onlinephpfunctions.com/code/7fc206640c2b79bcefaee606e7e56c7cfedda711), the only issue is that the index of each array is the name of the `Servico`, instead of a number, like your example. Do you know what could I change to reach your result with only one for? – afjm Nov 13 '17 at 13:09
  • No. Unfortunately you are not going to be able to employ php's automated array indexing on two levels within one foreach loop. I am sure the process can be done in one loop, but you would lose the auto-indexing (you would have to use counters and increment them conditionally -- created convoluted code). I recommend two loops in this case. – mickmackusa Nov 13 '17 at 13:16
  • That's what I thought. I will use two loops then. Thank you very much for your answer. Problem was solved! – afjm Nov 13 '17 at 13:21
0

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.

Andreas
  • 23,610
  • 6
  • 30
  • 62
  • this works, but it doesn't put the name of the keys on each object, such as `Servico` and `children`. How could I do that? – afjm Nov 13 '17 at 12:50
0

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
romal tandel
  • 481
  • 12
  • 19
  • This method doesn't read the whole array. It returned to me only one child for each element. – afjm Nov 13 '17 at 12:52