Flatten multidimensional array concatenating keys
Thanks for all the given answers.
I have transformed it in the following, which is an improved version. It eliminates the need of a root prefix, does not need to use references, it is cleaner to read, and it has a better name:
function array_flat($array, $prefix = '')
{
$result = array();
foreach ($array as $key => $value)
{
$new_key = $prefix . (empty($prefix) ? '' : '.') . $key;
if (is_array($value))
{
$result = array_merge($result, array_flat($value, $new_key));
}
else
{
$result[$new_key] = $value;
}
}
return $result;
}
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
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);
PHP convert nested array to single array while concatenating keys?
Something like this:
function makeNonNestedRecursive(array &$out, $key, array $in){
foreach($in as $k=>$v){
if(is_array($v)){
makeNonNestedRecursive($out, $key . $k . '_', $v);
}else{
$out[$key . $k] = $v;
}
}
}
function makeNonNested(array $in){
$out = array();
makeNonNestedRecursive($out, '', $in);
return $out;
}
// Example
$fooCompressed = makeNonNested($foo);
PHP - Concatenate / cascade multidimensional array keys
I think this should do it:
public function iterateKeys(array $array, $joiner, $prepend = NULL) {
if (!isset($formattedArray)) {
$formattedArray = array();
}
foreach ($array as $key => $value) {
if(is_array($value)) {
$formattedArray = array_merge($formattedArray, $this->iterateKeys($value, $joiner, $prepend . $joiner . $key));
} else {
$formattedArray[] = $prepend . $joiner . $key;
}
}
return $formattedArray;
}
Since the recursive call returns an array, you need to use array_merge
to combine it with what you currently have. And for the non-array case, you need to push the new string onto the array, not replace the array with a string.
Flatten multidimensional associative array to one one-dimensional array of references in PHP
header('content-type:text/plain');
$arr = array(
'a' => array(
'b' => array(
'c' => 'hello',
),
),
'd' => array(
'e' => array(
'f' => 'world',
),
),
);
//prime the stack using our format
$stack = array();
foreach ($arr as $k => &$v) {
$stack[] = array(
'keyPath' => array($k),
'node' => &$v
);
}
$lookup = array();
while ($stack) {
$frame = array_pop($stack);
$lookup[join('/', $frame['keyPath'])] = &$frame['node'];
if (is_array($frame['node'])) {
foreach ($frame['node'] as $key => &$node) {
$keyPath = array_merge($frame['keyPath'], array($key));
$stack[] = array(
'keyPath' => $keyPath,
'node' => &$node
);
$lookup[join('/', $keyPath)] = &$node;
}
}
}
var_dump($lookup);
// check functionality
$lookup['a'] = 0;
$lookup['d/e/f'] = 1;
var_dump($arr);
Alternatively you could have done stuff like this to get a reference /w array_pop functionality
end($stack);
$k = key($stack);
$v = &$stack[$k];
unset($stack[$k]);
That works because php arrays have elements ordered by key creation time. unset() deletes the key, and thus resets the creation time for that key.
Transparently flatten an array
Example usage of RecursiveArrayIterator
$array = array(
0 => 'a',
1 => array('subA','subB',array(0 => 'subsubA', 1 => 'subsubB', 2 => array(0 => 'deepA', 1 => 'deepB'))),
2 => 'b',
3 => array('subA','subB','subC'),
4 => 'c'
);
foreach (return new RecursiveIteratorIterator(new RecursiveArrayIterator($array))
as $key => $val) {
printf(
'%s: %s' . "\n",
$key, $val
);
}
/* Output:
0: a
0: subA
1: subB
0: subsubA
1: subsubB
0: deepA
1: deepB
2: b
0: subA
1: subB
2: subC
4: c
*/
extending RecursiveIteratorIterator
to return the current key-stack
class MyRecursiveIteratorIterator extends RecursiveIteratorIterator
{
public function key() {
return json_encode($this->getKeyStack());
}
public function getKeyStack() {
$result = array();
for ($depth = 0, $lim = $this->getDepth(); $depth < $lim; $depth += 1) {
$result[] = $this->getSubIterator($depth)->key();
}
$result[] = parent::key();
return $result;
}
}
foreach ($it = new MyRecursiveIteratorIterator(new RecursiveArrayIterator($array))
as $key => $val) {
printf('%s (%s): %s' . "\n", implode('.', $it->getKeyStack()), $key, $val);
}
/* Output:
0 ([0]): a
1.0 ([1,0]): subA
1.1 ([1,1]): subB
1.2.0 ([1,2,0]): subsubA
1.2.1 ([1,2,1]): subsubB
1.2.2.0 ([1,2,2,0]): deepA
1.2.2.1 ([1,2,2,1]): deepB
2 ([2]): b
3.0 ([3,0]): subA
3.1 ([3,1]): subB
3.2 ([3,2]): subC
4 ([4]): c
*/
Yet another version, using no RecursiveArrayIterator this time:
function flatten(array $array = array(), $keyStack = array(), $result = array()) {
foreach ($array as $key => $value) {
$keyStack[] = $key;
if (is_array($value)) {
$result = flatten($value, $keyStack, $result);
}
else {
$result[] = array(
'keys' => $keyStack,
'value' => $value
);
}
array_pop($keyStack);
}
return $result;
}
foreach (flatten($array) as $element) {
printf(
'%s: %s (depth: %s)' . "\n",
implode('.', $element['keys']),
$element['value'],
sizeof($element['keys'])
);
}
/*
0: a (depth: 1)
1.0: subA (depth: 2)
1.1: subB (depth: 2)
1.2.0: subsubA (depth: 3)
1.2.1: subsubB (depth: 3)
1.2.2.0: deepA (depth: 4)
1.2.2.1: deepB (depth: 4)
2: b (depth: 1)
3.0: subA (depth: 2)
3.1: subB (depth: 2)
3.2: subC (depth: 2)
4: c (depth: 1)
*/
From multidimensional array to other shape in Keras
I am not sure on which axis you want to concatenate, but you will have to flatten your tensor if you want a 1D output:
import tensorflow as tf
inp1 = tf.keras.layers.Input((128, 5))
inp2 = tf.keras.layers.Input((128, 5))
inp3 = tf.keras.layers.Input((128, 5))
inp4 = tf.keras.layers.Input((128, 5))
conc = tf.keras.layers.Concatenate(axis=1)([inp1, inp2, inp3, inp4])
flatten = tf.keras.layers.Flatten()(conc)
dense = tf.keras.layers.Dense(100)(flatten)
drp= tf.keras.layers.Dropout(0.1)(dense)
output = tf.keras.layers.Dense(4)(drp)
model = tf.keras.Model([inp1, inp2, inp3, inp4], output)
batch_size = 5
inputs1, inputs2, inputs3, inputs4 = tf.random.normal((5, 128, 5)), tf.random.normal((5, 128, 5)), tf.random.normal((5, 128, 5)), tf.random.normal((5, 128, 5))
print(model([inputs1, inputs2, inputs3, inputs4]).shape)
(5, 4)
You will, however, probably run into an "Out Of Memory" error using such large input shapes.
Related Topics
How to Get Greenwich Mean Time in PHP
Run Cron Job on PHP Script, on Localhost in Windows
PHP Function Use Variable from Outside
Save PHP Variables to a Text File
In PHP, How to Detect the Execution Is from Cli Mode or Through Browser
Passing PHP Objects to JavaScript
Xmlparseentityref: No Name' Warnings While Loading Xml into a PHP File
Prevent Direct Url Access to PHP File
New Csrf Token Per Request or Not
Symfony 2 Entitymanager Injection in Service
How to Solve Time Out in PHPmyadmin
Using the PHP Http_Accept_Language Server Variable
Best Practice: Import MySQL File in PHP; Split Queries