Convert Flat Array to the Multi-Dimensional

Convert flat array to the multi-dimensional

I don't think there is a built-in function in PHP that does this.

I tried the following code, and it seems to work to prepare the nested array the way you describe:

$nodes = array();
$tree = array();
foreach ($source as &$node) {
$node["Children"] = array();
$id = $node["Menu"]["id"];
$parent_id = $node["Menu"]["parent_id"];
$nodes[$id] =& $node;
if (array_key_exists($parent_id, $nodes)) {
$nodes[$parent_id]["Children"][] =& $node;
} else {
$tree[] =& $node;
}
}

var_dump($tree);

I wrote a similar algorithm in a PHP class I wrote for my presentation Hierarchical Models in SQL and PHP, but I was using objects instead of plain arrays.

Convert flat array to multidimensional array with dynamic keys. Is it possible?

With a variable array of columns you need to group in hierarchical order, you'll certainly want a recursive solution to this problem. For each step in your recursive calls, check to see if a particular grouping level exists yet, and if not, then initialize it. Group using associative arrays for your items, then convert to flat arrays after. It's very simple conceptually, although perhaps a little confusing to look at:

function aggregateData($data, $db_row, $columns, $first_column = true) {
// Base case: with no more columns left, we just take the sum and return.
if(empty($columns)) {
$data['summary'] += $db_row['sum1'];
return $data;
}

$column = array_shift($columns);
$value = $db_row[$column];
if($first_column) {
// First column is a special case. We don't add anything here because every level's summary is the sum of its nested items.
if(!array_key_exists($value, $data)) {
$data[$value] = [
'key'=>$value,
'items'=>empty($columns) ? null : [],
'summary'=>0
];
}

$data[$value] = aggregateData($data[$value], $db_row, $columns, false);
} else {
// For all other columns, we add the sum to each nested level.
if(!array_key_exists($value, $data['items'])) {
$data['items'][$value] = [
'key'=>$value,
'items'=>empty($columns) ? null : [],
'summary'=>0
];
}

$data['summary'] += $db_row['sum1'];
$data['items'][$value] = aggregateData($data['items'][$value], $db_row, $columns, false);
}

return $data;
}

function flattenData($data) {
foreach($data as $key=>$value) {
if(is_null($value['items'])) {
break;
}

$data[$key]['items'] = flattenData($value['items']);
}

return array_values($data);
}

$db_rows = /* your DB retrieval code here */;
$columns = /* columns to group by in hierarchical order */;
$data = [];
foreach($db_rows as $db_row) {
$data = aggregateData($data, $db_row, $columns);
}

$data = flattenData($data);

To help understand what's going on, consider the top-most level, grouping by state. After the aggregateData() calls, before flattening the arrays, it will produce a structure that looks like the following:

{
"Luanda": {
"key": "Luanda",
"items": {...},
"summary": ...,
},
"Benguela": {
"key": "Benguela",
"items": {...},
"summary": ...,
}
}

Notice that because each entry is associated with its key in an object, instead of an index in an array, this allows for easy lookups so we can aggregate information at each level. After flattening, we instead get this:

[
{
"key": "Luanda",
"items": [...],
"summary": ...,
},
{
"key": "Benguela",
"items": [...],
"summary": ...,
}
]

Each entry is no longer associated with its key, instead being the desired flat array. We lose the ability to do simple lookups, but we no longer need that capability at the end of our calculations.

The above doesn't solve the entirety of your problem as there are points of data not being included in this result, but as stackoverflow is not a free coding service and you have not provided any of your own code, I will be leaving the necessary modifications as an exercise. This should, however, remove the bulk of the work required and serve as a strong starting point for your solution.

How to convert between flat and multidimensional arrays without copying data?

The most correct way has been given by @Maxim Egorushkin and @ypnos: double *flat = &multi[0][0];. And it will work fine with any decent compiler. But unfortunately is not valid C++ code and invokes Undefined Bahaviour.

The problem is that for an array double multi[N][M]; (N and M being compile time contant expressions), &multi[0][0] is the address of the first element of an array of size M. So it is legal to do pointer arithmetics only up to M. See this other question of mine for more details.

How to Flatten a Multidimensional Array?

You can use the Standard PHP Library (SPL) to "hide" the recursion.

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));
foreach($it as $v) {
echo $v, " ";
}

prints

1 2 3 4 5 6 7 8 9 

How to flatten a multi-dimensional array to simple one in PHP?

Use array_walk_recursive

<?php

$aNonFlat = array(
1,
2,
array(
3,
4,
5,
array(
6,
7
),
8,
9,
),
10,
11
);

$objTmp = (object) array('aFlat' => array());

array_walk_recursive($aNonFlat, create_function('&$v, $k, &$t', '$t->aFlat[] = $v;'), $objTmp);

var_dump($objTmp->aFlat);

/*
array(11) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
[5]=>
int(6)
[6]=>
int(7)
[7]=>
int(8)
[8]=>
int(9)
[9]=>
int(10)
[10]=>
int(11)
}
*/

?>

Tested with PHP 5.5.9-1ubuntu4.24 (cli) (built: Mar 16 2018 12:32:06)

Convert multi-dimensional array to flat array php

You can use a recursive function like this:

function flatten($array, $parent_key = '1') {
$flattened_array = [];
foreach ($array as $key => $item) {
$tmp = $item;
unset($tmp['conditions']);
$child_key = $parent_key . '--' . strval($key + 1);
$flattened_array[$child_key] = $tmp;
if (isset($item['conditions'])) {
$flattened_array = array_merge($flattened_array, flatten($item['conditions'], $child_key));
}
}
return $flattened_array;
}

$input = [
0 => [
'type' => 'MagentoCatalogRuleModelRuleConditionCombine',
'aggregator' => 'all',
'conditions' => [
0 => [
'type' => 'MagentoCatalogRuleModelRuleConditionProduct',
'attribute' => 'category_ids'
]
]
],

1 => [
'type' => 'MagentoCatalogRuleModelRuleConditionProduct',
'attribute' => 'category_ids'
],

2 => [
'type' => 'MagentoCatalogRuleModelRuleConditionProduct',
'attribute' => 'attribute_set_id'
]
];

print_r(flatten($input));

Output:

Array
(
[1--1] => Array
(
[type] => MagentoCatalogRuleModelRuleConditionCombine
[aggregator] => all
)

[1--1--1] => Array
(
[type] => MagentoCatalogRuleModelRuleConditionProduct
[attribute] => category_ids
)

[1--2] => Array
(
[type] => MagentoCatalogRuleModelRuleConditionProduct
[attribute] => category_ids
)

[1--3] => Array
(
[type] => MagentoCatalogRuleModelRuleConditionProduct
[attribute] => attribute_set_id
)

)

Merge/flatten an array of arrays



ES2019

ES2019 introduced the Array.prototype.flat() method which you could use to flatten the arrays. It is compatible with most environments, although it is only available in Node.js starting with version 11, and not at all in Internet Explorer.

const arrays = [
["$6"],
["$12"],
["$25"],
["$25"],
["$18"],
["$22"],
["$10"]
];
const merge3 = arrays.flat(1); //The depth level specifying how deep a nested array structure should be flattened. Defaults to 1.
console.log(merge3);


Related Topics



Leave a reply



Submit