Basheer Ahmed Basheer Ahmed - 7 months ago 10
PHP Question

Complex merge function with PHP

I've been struggling around whole day by creating

merge function
for multidimensional array. The scenario is little different to elaborate in words instead I would try to explain it with practical example.

$actual_array = [

'assets' => [1, 2, 3],
'liabilities' => [1, 2, 3, 4, 5, 6],
'equity' => [1],
'income' => [1, 2, 3, 4],
'expenses' => [1, 2, 3]
];

$merge = [
'balance_sheet' => ['assets', 'liabilities', 'equity'],
'income' => ['income', 'expenses'],
];

self::merge( $merge, $actual_array );


Function that will merge the columns

public static function merge( array $merges, array $data )
{
$bigger_array_length = 0;
$arr = [];
$columns = [];

foreach ($merges as $key => $merge) {

foreach ($merge as $index => $column) {

//check which array has bigger length in the iteration
if($bigger_array_length < count($data[$column]))
$bigger_array_length = count($data[$column]);

$columns[] = $column;

}
//when i die and dump the columns array on its first iterate
dd($columns); // assets, liabilities, equity
if($bigger_array_length> 0) {

$total_columns = count($columns);// on first iteration 3 assets, liabilities and equity
for($i = 0; $i < $bigger_array_length; $i++) {
//
$arr[$key][] = [
$columns[$total_columns - 1] => isset($data[ $columns[$total_columns - 1] ][$i]) ? $data[ $columns[$total_columns - 1] ][$i] : 0,
$columns[$total_columns - 2] => isset($data[ $columns[$total_columns - 2] ][$i]) ? $data[ $columns[$total_columns - 2] ][$i] : 0,
$columns[$total_columns - 3] => isset($data[ $columns[$total_columns - 3] ][$i]) ? $data[ $columns[$total_columns - 3] ][$i] : 0
];

}


}
//when i die and dump on first iteration then it's just fine
array:1 [▼
"balance_sheet" => array:6 [▼
0 => array:3 [▼
"equity" => 1
"liabilities" => 1
"assets" => 1
]
1 => array:3 [▼
"equity" => 0
"liabilities" => 2
"assets" => 2
]
2 => array:3 [▼
"equity" => 0
"liabilities" => 3
"assets" => 3
]
3 => array:3 [▼
"equity" => 0
"liabilities" => 4
"assets" => 0
]
4 => array:3 [▼
"equity" => 0
"liabilities" => 5
"assets" => 0
]
5 => array:3 [▼
"equity" => 0
"liabilities" => 6
"assets" => 0
]
]
]
$columns = [];

}

}


I'm just stuck here and can not figure out how to make it dynamic.

[$total_columns - 1] // the 1, 2, 3 or so on
//something like [$total_columns - $i]


So if I let the foreach for second iteration then it output
undefined index error
.

e.x
[$total_columns - 3]
will result
-1 index
on second iteration because second iteration have only
2 total columns
.

which will result in
Undefined offset: -1
.

What I want to achieve

"balance_sheet" => array:6 [▼
0 => array:3 [▼
"equity" => 1
"liabilities" => 1
"assets" => 1
]
1 => array:3 [▼
"equity" => 0
"liabilities" => 2
"assets" => 2
]
2 => array:3 [▼
"equity" => 0
"liabilities" => 3
"assets" => 3
]
3 => array:3 [▼
"equity" => 0
"liabilities" => 4
"assets" => 0
]
4 => array:3 [▼
"equity" => 0
"liabilities" => 5
"assets" => 0
]
5 => array:3 [▼
"equity" => 0
"liabilities" => 6
"assets" => 0
]
],
"income" => array:4 [▼
0 => array:2 [▼
"expenses" => 1
"income" => 1
]
1 => array:2 [▼
"expenses" => 2
"income" => 2
]
2 => array:2 [▼
"expenses" => 3
"income" => 3
]
3 => array:2 [▼
"expenses" => 0
"income" => 4
]
]
]


Any help would be much appreciated.
Thanks

Answer
function spec_merge($arr) {
   // find max length of array items
   $m = max(array_map(count, $arr));

   // fill array items to max length by 0
   $a = array_map(function($i) use($m) {
           return ($m - count($i)) ? 
                   $i + array_fill(count($i), $m - count($i), 0) :
                   $i; }, 
        $arr);

   // make array of sourse keys     
   $keys = array_keys($a);

   // transpose array
   array_unshift($a, null);
   $a = call_user_func_array("array_map", $a);

   // set correct keys
   $a = array_map(function ($i) use($keys) {
           return array_combine($keys, $i); }, 
        $a);
   return $a;  
}

$new = spec_merge([
     'assets' => [1, 2, 3],
     'liabilities' => [1, 2, 3, 4, 5, 6],
     'equity' => [1]
     ]);

print_r($new); 

result

  [[
    [assets] => 1
    [liabilities] => 1
    [equity] => 1
  ][
    [assets] => 2
    [liabilities] => 2
    [equity] => 0
  ][            
    [assets] => 3
    [liabilities] => 3
    [equity] => 0
  ][
    [assets] => 0
    [liabilities] => 4
    [equity] => 0
  ][
    [assets] => 0
    [liabilities] => 5
    [equity] => 0
  ][
    [assets] => 0
    [liabilities] => 6
    [equity] => 0
  ]]

demo