Flatten Multidimensional Array Concatenating Keys

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



Leave a reply



Submit