Search code examples
phparraysmultidimensional-arraygroupingsub-array

Group row data from a 2d array by one column, remove one column, and populate a subarray from another column


I have an array with values like:

$menuArray = [
    [
        'parent' => 'Basic',
        'parentId' => 1,
        'child' => 'Birthday',
        'childId' => 2,
    ],
    [
        'parent' => 'Basic',
        'parentId' => 1,
        'child' => 'Gender',
        'childId' => 3,
    ],
    [
        'parent' => 'Geo',
        'parentId' => 10,
        'child' => 'Current City',
        'childId' => 11,
    ],
    [
        'parent' => 'Known me',
        'parentId' => 5,
        'child' => 'My personality',
        'childId' => 7,
    ],
    [
        'parent' => 'Known me',
        'parentId' => 5,
        'child' => 'Best life moment',
        'childId' => 8,
    ],
];

And I want to group this array on parent (or parentId) and the final result would be like:

[
    [
        'parent' => 'Basic',
        'parentId' => 1,
        'child' => ['Birthday', 'Gender'],
    ],
    [
        'parent' => 'Geo',
        'parentId' => 10,
        'child' => ['Current City'],
    ],
    [
        'parent' => 'Known me',
        'parentId' => 5,
        'child' => ['My personality', 'Best life moment'],
    ],
]

My current code:

$filter = [];
$f = 0;
for ($i = 0; $i < count($menuArray); $i++) {
    $c = 0;
    for ($b = 0; $b < count($filter); $b++) {
        if ($filter[$b]['parent'] == $menuArray[$i]['parent']) {
            $c++;
        }
    }
    if ($c == 0) {
        $filter[$f]['parent'] = $menuArray[$i]['parent'];
        $filter[$f]['parentId'] = $menuArray[$i]['parentId'];
        $filter[$f]['child'][] = $menuArray[$i]['child'];
        $f++;
    } 
}

But it doesn't push child values from subsequent encounters of a parent-related row into the result array.


Solution

  • Try:

    $filter = array();
    foreach ($menuArray as $menu) {
      if (!array_key_exists($menu['parent_id'], $filter)) {
        $filter[$menu['parent_id']] = array(
          'parent' => $menu['parent'],
          'parent_id' => $menu['parent_id'],
          'child' => array()
        );
      }
      $filter[$menu['parent_id']]['child'][$menu['child_id']] = $menu['child'];
    }
    

    This will produce an array like:

    Array
    (
        [1] => Array
            (
                [parent] => Basic
                [parentId] => 1
                [child] => Array
                    (
                        [2] => Birthday
                        [3] => Gender
                    )
    
            )
    
        [10] => Array
            (
                [parent] => Geo
                [parentId] => 10
                [child] => Array
                    (
                        [11] => Current City                  
                    )
    
            )
    
        [5] => Array
            (
                [parent] => Known me
                [parentId] => 5
                [child] => Array
                    (
                        [7] => My personality
                        [8] => Best life moment
                    )
    
            )
    )
    

    Notice that the array indexes match the IDs. You can't loop this with a for loop but you can foreach ($filter as $parent_id=>$parent) correctly. If you want to you can change line 4 of my code to $filter['key_' . $menu['parent_id']] to force a string and a for loop will work