robotmay
robotmay

Reputation: 1316

Push row data from a 2d array as subarrays into a 2d grouping array to form a 3-level array

If I wanted to associate items from one array with another array via identical values, eg. items.group_id -> groups.group_id, is there an array function to do that neatly?

I have two arrays:

$items = [
    ['group_id' => 456, 'item_id' => 123, /* Rest of details */],
    ['group_id' => 457, 'item_id' => 124, /* Rest of details */],
    ['group_id' => 457, 'item_id' => 125, /* Rest of details */],
    ['group_id' => 456, 'item_id' => 126, /* Rest of details */],
];

$groups = [
    ['group_id' => 456, 'group_name' => 'General'],
    ['group_id' => 457, 'group_name' => 'Ungeneral'],
];

And the result I want is:

$groups = [
    [
         'group_id' => 456,
         'group_name' => 'General'
         [
              'item_id' => 123,
              // Rest of details
         ],
         [
              'item_id' => 126,
              // Rest of details
         ],
    ],
    [
         'group_id' => 457,
         'group_name' => 'Ungeneral',
         [
              'item_id' => 124,
              // Rest of details
         ],
         [
              'item_id' => 125,
              // Rest of details
         ],
     ],
];

Upvotes: -1

Views: 259

Answers (4)

mickmackusa
mickmackusa

Reputation: 47874

As an improvement on Amber's solution, I prefer to make references to each of the rows in the $groups array, then iterate the $items, isolate (and the remove) the identifying column value, the push the remaining elements of the item as a new subarray into its appropriate row reference. As Amber mentioned, isset() is used to check if an item belongs in the $groups array at all. Notice also that there are no furst level associative keys in my result.

Code: (Demo)

$items = [
    ['group_id' => 456, 'item_id' => 123, 'foo' => 'bar'],
    ['group_id' => 457, 'item_id' => 124, 'foo' => 'bar'],
    ['group_id' => 457, 'item_id' => 125, 'foo' => 'bar'],
    ['group_id' => 456, 'item_id' => 126, 'foo' => 'bar'],
];

$groups = [
    ['group_id' => 456, 'group_name' => 'General'],
    ['group_id' => 457, 'group_name' => 'Ungeneral'],
];

foreach ($groups as &$row) {
    $ref[$row['group_id']] =& $row;
}
foreach ($items as $item) {
    $id = $item['group_id'];
    if (isset($ref[$id])) {
        unset($item['group_id']);
        $ref[$id][] = $item;
    }
}
var_export($groups);

Output:

array (
  0 => 
  array (
    'group_id' => 456,
    'group_name' => 'General',
    0 => 
    array (
      'item_id' => 123,
      'foo' => 'bar',
    ),
    1 => 
    array (
      'item_id' => 126,
      'foo' => 'bar',
    ),
  ),
  1 => 
  array (
    'group_id' => 457,
    'group_name' => 'Ungeneral',
    0 => 
    array (
      'item_id' => 124,
      'foo' => 'bar',
    ),
    1 => 
    array (
      'item_id' => 125,
      'foo' => 'bar',
    ),
  ),
)

Upvotes: 0

robotmay
robotmay

Reputation: 1316

I found a solution that works for me, with some help from your solutions chaps.

$links_by_group = array();
        foreach($links as $link) {
            $linked_groups = $this->return_linked_groups($link['link_id']);
            foreach($linked_groups as $group){
                $links_by_group[$group][$link['link_id']] = $link;
            }
        }

Thanks for the help!

Upvotes: 0

gnarf
gnarf

Reputation: 106332

It would be easier if you keyed your groups array by the id instead of numerical indexes

$newArray = array();
foreach($groups as $group) {
  // add the group, and an items array we can append to later.
  $newArray[$group['group_id']] = $group;
  $newArray[$group['group_id']]['items'] = array();  
}
foreach ($items as $item) {
  $newArray[$item['group_id']]['items'][] = $item;
}

Should result in an array like this:

$newArray = array(
   [456] => array(
     'group_id' => 456,
     'group_name' => 'General'
     'items' => array(
       [0] => array(
         'item_id' => 123,
         // Rest of details
       );
       [1] => array(
         'item_id' => 126,
         // Rest of details
         );
       );
     );

Upvotes: 2

Amber
Amber

Reputation: 526573

I don't think there's a built-in function to do this, but here's some basic code that should handle it:

<?php
    // First, group the items by their group_id
    $items_by_group = array();
    foreach($items as $item) {
        $items_by_group[$item['group_id']][] = $item;
    }

    // Second, go through the groups and if they have any associated items,
    // add them to that group's array.
    foreach($groups as $key => $value) {
        if(isset($items_by_group[$value['group_id']])) {
            foreach($items_by_group[$value['group_id']] as $ikey => $ivalue) {
                unset($ivalue['group_id']);
                $groups[$key][$ikey] = $ivalue;
            }
        }
    }
?>

Note that the above code safely handles cases where you have items with an invalid group id (one for a group that's not defined - it'll ignore those items).

Upvotes: 4

Related Questions