Reputation: 13
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
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
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
)
)
Upvotes: 0
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);
Upvotes: 0
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