DFA
DFA

Reputation: 13

Group 2d array data into sets of recurring second level keys

I am struggling with an array that I need to convert into a new array based on the unique array keys. Each array represents just a part of the desired result. I need [menu_name], [menu_url] and [menu_target] as keys in each row.

The way I see it, to achieve this is to construct a new array, each time an array_key_exist() in the array. But I am unable to achieve this.

$array = [
    ['menu_name' => 'Contact'],
    ['menu_url' => '/contact'],
    ['menu_target' => '_blank'],
    ['menu_name' => 'Home'],
    ['menu_url' => '/home'],
    ['menu_target' => '_self'],
];

The desired array I want to create looks like this:

Array
(
    [0] => Array
    (
    [menu_name] => Contact,
    [menu_url] => /contact,
    [menu_target] => _blank
    )
    [1] => Array
    (
    [menu_name] => Home,
    [menu_url] => /home,
    [menu_target] => _blank
    )
)

Here is my code so far (incomplete):

$result = array();
foreach($array as $option => $value)
{
    $result[$value->option_key] = $value->option_value;
    $new_array = array();
    if(array_key_exist($value->option_key, $new_array))
    {
        // here is where I get stuck….
    print_r($new_array);
    }
}

Upvotes: 1

Views: 117

Answers (4)

mickmackusa
mickmackusa

Reputation: 47764

If you don't know in advance how many rows belong in each group, push reference variables into the result array each time a reference (group) shares a key with the current row's key. While encountering new keys in each group, use the array union assignment operator to append the new associative element to the reference.

Code: (Demo)

$array = [
    ['menu_name' => 'Contact'],
    ['menu_url' => '/contact'],
    ['menu_target' => '_blank'],
    ['menu_name' => 'Home'],
    ['menu_url' => '/home'],
    ['menu_target' => '_self'],
];

$result = [];
foreach ($array as $row) {
    if (!isset($ref) || key_exists(key($row), $ref)) {
        unset($ref);
        $ref = $row;
        $result[] =& $ref;
        continue;
    }
    $ref += $row;
}
var_export($result);

If you know that the groups will always have 3 elements, then just chunk and flatten. (Demo)

var_export(
    array_map(
        fn($chunk) => array_merge(...$chunk),
        array_chunk($array, 3)
    )
);

Both Output:

array (
  0 => 
  array (
    'menu_name' => 'Contact',
    'menu_url' => '/contact',
    'menu_target' => '_blank',
  ),
  1 => 
  array (
    'menu_name' => 'Home',
    'menu_url' => '/home',
    'menu_target' => '_self',
  ),
)

Upvotes: 0

Darren
Darren

Reputation: 13128

Provided your answer is always grouped by threes, as posted in your example.

This is an alternative method to djidi's answer incase you wanted to see it done with silly loops.

    $new = array_chunk($a, 3);

    $d = array();
    foreach($new as $i => $group) {
        foreach($group as $index => $item) {
            foreach($item as $name=>$val) {
                $d[$i][$name] = $val;
            }
        }
    }

Which returns:

Array
(
    [0] => Array
        (
            [menu_name] => Contact
            [menu_url] => /contact
            [menu_target] => _blank
        )

    [1] => Array
        (
            [menu_name] => Home
            [menu_url] => /home
            [menu_target] => _self
        )
)

Example Demo

Upvotes: 0

user1978142
user1978142

Reputation: 7948

Another way, is if the current batch of keys are complete, go to the next one and fill up the next one. Example:

$values = array(array('menu_name' => 'Contact'),array('menu_url' => '/contact'),array('menu_target' => '_blank'),array('menu_name' => 'Home'),array('menu_url' => '/home'),array('menu_target' => '_self'),);
$new_values = array();
$x = 0;
$columns = array_unique(array_map(function($var){
    return key($var);
}, $values));

foreach($values as $value) {
    $current_key = key($value);
    $new_values[$x][$current_key] = reset($value);
    if(array_keys($new_values[$x]) == $columns) $x++;
}

echo '<pre>';
print_r($new_values);

Sample Demo

Upvotes: 0

fdehanne
fdehanne

Reputation: 1718

You can use a var you increment each time key already exists :

$result = array();
$i = 0;

foreach($array as $option => $value)
{
    if ( array_key_exists($value->option_key, $result[$i]) ) $i++;

    $result[$i][$value->option_key] = $value->option_value;
}

Upvotes: 2

Related Questions