Flatten multidimensional array of numbers recursively - php

Let's say I have an array like this
Array
(
[0] => 123
[180] => Array
(
[400] => Array
(
[0] => 474
[1] => 395
[2] => 994
[3] => 365
)
)
[1] => 144
[2] => 119
)
I would like to go though this array and generate a one dimensional array that contains all the numbers. In the loop, if we get an array, then the number is the corresponding array key.
I did something like this but it doesn't work:
function flatten_array($data) {
$result = array();
foreach ($data as $key => $value) {
if(is_array($value)) {
$result[] = $key;
flatten_array($value);
} else {
$result[] = $value;
}
}
return $result;
}
The resulting array I should get should be this one:
$result = Array
(
[0] => 123
[1] => 180
[2] => 400
[3] => 474
[4] => 395
[5] => 994
[6] => 365
[7] => 144
[8] => 119
)
Any help will be appreciated thanks.

There are some helpful libraries in composer, for example this one: https://packagist.org/packages/nikic/iter
With this lib you can flatten the data the following way:
$result = toArray(flatten($data));

Without using libraries, such result can be achieved this way:
function flattenArray(array $data) {
$values = array_values($data);
$result = [];
foreach ($values as $value) {
if (is_array($value)) {
$result = array_merge(flattenArray($value), $result);
} else {
$result[] = $value;
}
}
return $result;
}
P.S. Note the mistake in your original example:
$result[] = $key;
flatten_array($value);
You call the recursive function without using its returned result.
And you assign the key instead.

Your code doesn't accumulate a result anywhere. You could return arrays and merge them, but to save allocation overhead I recommend using a single result array and passing it by reference into your recursive walk function. Here's a complete example:
function flatten_array($a) {
function flatten($a, &$flat) {
foreach ($a as $k => $v) {
if (is_array($v)) {
$flat[] = $k;
flatten($v, $flat);
}
else {
$flat[] = $v;
}
}
}
$flat = [];
flatten($a, $flat);
return $flat;
}
$a = [
123,
180 => [
400 => [
474,
395,
994,
365,
]
],
144,
119
];
print_r(flatten_array($a));
If you expect your depth to be massive, you can do it iteratively to avoid an overflow. Note that this gives a breadth-first ordering:
function flatten_array($a) {
$flat = [];
for ($stack = [$a]; count($stack);) {
foreach (array_pop($stack) as $k => &$v) {
if (is_array($v)) {
$flat[] = $k;
$stack[] = $v;
}
else {
$flat[] = $v;
}
}
}
return $flat;
}

You can use next recursive function:
function array_flat($arr) {
$res = [];
foreach($arr as $key=>$val) {
if (is_array($val)) {
// element is array: Push key to result and merge recursion result
array_push($res, $key);
$res = array_merge($res, array_flat($val));
} else {
// push simple value to result
array_push($res, $val);
}
}
return $res;
}
print_r(array_flat($arr));
Try working PHP code o PHPize.online

Related

PHP format an array of arrays into a flat array

I have an generated array into this format and want to generated a second array to fit into a file that expects the specific format
This is the array i have :
(int) 0 => array(
[Service] => Array
(
[id] => 6948229
[document] => Array
(
[number] => 0003928425
)
)
This is the array i want to build from the previous array (will have many indexes)
verified[id]
verified[number]
So far i build this script:
foreach($data as $key=>$value )
{
echo '<br>key '.$key;
foreach($value as $k=>$v)
{
$Verified[$key]['id'] = $v["id"];
$Verified[$key]['number'] = $v['document']['number'];
But just get undefined index error message.
Which indexes i must use to get the flatten array ?
From what I can make from your question, you can do something like this to get the desired output,
$Verified = []; //use array() for versions below 5.5
foreach($data as $key=>$value )
{
echo '<br>key '.$key;
foreach($value as $k=>$v)
{
if(is_array($v)){
$Verified[$key]['number'] = $v['document']['number'];
}
$Verified[$key]['id'] = $v['id'];
Please pass your array to this function
function arrayconvert($arr) {
if (is_array($arr)) {
foreach($arr as $k => $v) {
if (is_array($v)) {
arrayconvert($v);
} else {
$newarr[$k] = $v;
}
}
}
return $newarr;
}
There is no need of second foreach and you are getting undefined index because you are using $v['id'] insted of $val['id'] in that line $Verified[$key]['id'] = $v["id"];
<?php
$data = array('Service' => array('id' => 6948229,'document' => array ('number' => '0003928425' )));
$verified = array();
foreach($data as $key => $val)
{
$verified[$key]['id'] = $val['id'];
$verified[$key]['number'] = $val['document']['number'];
}
echo "<pre>"; print_r($verified);
?>
output
Array
(
[Service] => Array
(
[id] => 6948229
[number] => 0003928425
)
)

php searching in multidimensional array of unknown depth

I try to select the data of an array that was constructed by json_decode().
In principle it is an multiarray of unknown dimension.
First of all, I want to search recursively for a value in this array. As a next step I want to get some other values of the upper dimension. So here is an example:
I search for: "2345"
....
$json[3][6]['journal']['headline']="news"
$json[3][6]['journal']['article']=2345
....
$json[8]['journal']['headline']="weather"
$json[8]['journal']['article']=2345
....
After that I want to get the value of the element headline (returning "news" and "weather")
It might be that the element 2345 can be found in different dimensions!!!
Someone could probably do this with a RecursiveIteratorIterator object, but I personally have a hard time with iterator objects, so here is a fairly robust system:
<?php
// This will traverse an array and find the
// value while storing the base key
class RecurseLocator
{
public static $saved = array();
public static $find;
public static $trigger;
public static function Initialize($find = false)
{
self::$find = $find;
}
public static function Recursive(array $array)
{
foreach($array as $key => $value) {
if(!isset(self::$trigger) || (isset(self::$trigger) && empty(self::$trigger))) {
if(is_numeric($key))
self::$trigger = $key;
}
if(!is_array($value)) {
if($value == self::$find) {
self::$saved[self::$trigger] = $value;
}
}
if(is_array($value)) {
$value = self::Recursive($value);
if(!is_numeric($key))
self::$trigger = "";
}
$return[$key] = $value;
}
return $return;
}
}
// This class will traverse an array searching
// for a specific key or keys
class RecurseSearch
{
public $data;
public $compare;
public function Find($array = '',$find,$recursive = true)
{
$find = (is_array($find))? implode("|",$find):$find;
if(is_array($array)) {
foreach($array as $key => $value) {
if(preg_match("/$find/",$key))
$this->compare[$key] = $value;
if($recursive == true) {
if(!is_array($value)) {
if(preg_match("/$find/",$key)) {
$this->data[$key][] = $value;
}
$array[$key] = $value;
}
else {
if(preg_match("/$find/",$key))
$this->data[$key][] = $this->Find($value,$find);
$array[$key] = $this->Find($value,$find);
}
}
else {
if(preg_match("/$find/",$key))
$this->data[$key] = $value;
}
}
$this->data = (isset($this->data))? $this->data:false;
return $this;
}
}
}
// This function just wraps the RecurseSearch class
function get_key_value($array = array(), $find = array(),$recursive = true)
{
$finder = new RecurseSearch();
return $finder->Find($array,$find,$recursive);
}
USAGE:
$json[3][6]['journal']['headline'] = "news";
$json[3][6]['journal']['article'] = 2345;
$json[8]['journal']['headline'] = "weather";
$json[8]['journal']['article'] = 2345;
$json[4][1]['journal']['headline'] = "news";
$json[4][1]['journal']['article'] = 22245;
$json[5]['journal']['headline'] = "weather";
$json[5]['journal']['article'] = 233345;
// Set the search criteria
RecurseLocator::Initialize(2345);
// Traverse the array looking for value
$arr = RecurseLocator::Recursive($json);
// If found, will be stored here
$iso = RecurseLocator::$saved;
/* $iso looks like:
Array
(
[3] => 2345
[8] => 2345
)
*/
// Loop through the $iso array
foreach($iso as $key => $value) {
// Save to new array your search results
$new[] = get_key_value($json[$key],array("headline","article"),true);
}
/* $new looks like:
Array
(
[0] => RecurseSearch Object
(
[data] => Array
(
[headline] => Array
(
[0] => news
)
[article] => Array
(
[0] => 2345
)
)
[compare] => Array
(
[headline] => news
[article] => 2345
)
)
[1] => RecurseSearch Object
(
[data] => Array
(
[headline] => Array
(
[0] => weather
)
[article] => Array
(
[0] => 2345
)
)
[compare] => Array
(
[headline] => weather
[article] => 2345
)
)
)
*/
?>
Just as a side note, the above class stores multiple found in the [data], and then stores them also in the [compare], however the [compare] will overwrite itself if multiple same-keys are found in one array where as [data] will just keep adding values.
just create a function for compile unknown array. try this
$json[1][6]['journal']['headline']="news";
$json[1][6]['journal']['article']=2345;
$json[3][6]['journal']['headline']="HOT";
$json[3][6]['journal']['article']=2345;
$json[8]['journal']['headline']="weather";
$json[8]['journal']['article']=2345;
$json[10]['journal']['headline']="weather";
$json[10]['journal']['article']=2345;
$GLOBALS['list_scan'] = array();
$result = array();
foreach ($json as $key => $value)
{
if (is_array($value)) {
_compile_scan($key, $value);
}
}
echo "<pre>";
print_r($GLOBALS['list_scan']);
echo "</pre>";
$search = "2345";
$keyword = "article";
$keyFinder = "headline";
foreach ($GLOBALS['list_scan'] as $key => $value)
{
if ($value == $search)
{
$addr = substr($key, 0, -(strlen($keyword))).$keyFinder;
if (!empty($GLOBALS['list_scan'][$addr]))
{
$result[] = $GLOBALS['list_scan'][$addr];
}
}
}
echo "<pre>";
print_r($result);
echo "</pre>";
function _compile_scan($index, $value)
{
$pointer =& $GLOBALS['list_scan'];
foreach ($value as $key => $val)
{
$temp = '';
$temp = $index.'|'.$key;
if (is_array($val))
{
// $pointer[$temp] = $val;
_compile_scan($temp, $val);
}
else $pointer[$temp] = $val;
}
}
output:
Array
(
[1|6|journal|headline] => news
[1|6|journal|article] => 2345
[3|6|journal|headline] => HOT
[3|6|journal|article] => 2345
[8|journal|headline] => weather
[8|journal|article] => 2345
[9|journal|headline] => Others
[9|journal|article] => 234521
)
Array
(
[0] => news
[1] => HOT
[2] => weather
)

recursive search an array on the basis of key in php

I need a php function that will recursively search an array on the basis of key I provided. and want to get an array as return output containing all the values those are mapped with the searched key.
For e.g.:
[Case] => Array
(
[0] => Array
(
[CASE_ID] => 2233
[CHECK_ID] => 57
[CLIENT_ID] => 78
)
[2] => Array
(
[CASE_ID] => 9542
[CHECK_ID] => 45
[CLIENT_ID] => 18
)
)
If I would pass this array and key CHECK_ID, then it should return me an array containing 57,45. Kindly ask if you need more explanation. Thanks in Advance.
Walking the array and chucking found keys into a new one:
function find_matches($array, $value) {
$found = array();
array_walk_recursive($array,
function ($item, $key) use ($value, &$found) {
if ($value === $key) {
$found[] = $item;
}
}
);
return $found;
}
see http://codepad.viper-7.com/dVmYOT
Have you also considered using find('list') with a fields condition restriction?
Just check each element, filter based on key, convert the outcome to an array:
$filter = function($c, $key) {
return $key === 'CHECK_ID';
};
$filtered = new CallbackFilterIterator(
new RecursiveIteratorIterator(
new RecursiveArrayIterator($array)
),
$filter
);
var_dump(iterator_to_array($filtered, false));
Result:
array(2) {
[0] =>
int(57)
[1] =>
int(45)
}
function array_rfind($find, $arr) {
$found = array();
foreach($arr as $key => $val) {
if($key == $find)
$found[] = $val;
elseif(is_array($val))
$found = array_merge($found, array_rfind($find, $val));
}
return $found;
}

Simplify a nested array into a single level array [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How to Flatten a Multidimensional Array?
Let's say I have an array like this:
array (
1 =>
array (
2 =>
array (
16 =>
array (
18 =>
array (
),
),
17 =>
array (
),
),
),
14 =>
array (
15 =>
array (
),
),
)
How would I go about tranforming it into array like this?
array(1,2,16,18,17,14,15);
Sorry for the closevote. Didnt pay proper attention about you wanting the keys. Solution below:
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($arr),
RecursiveIteratorIterator::SELF_FIRST);
$keys = array();
and then either
$keys = array();
foreach($iterator as $key => $val) {
$keys[] = $key;
}
or with the iterator instance directly
$keys = array();
for($iterator->rewind(); $iterator->valid(); $iterator->next()) {
$keys[] = $iterator->key();
}
or more complicated than necessary
iterator_apply($iterator, function(Iterator $iterator) use (&$keys) {
$keys[] = $iterator->key();
return TRUE;
}, array($iterator));
gives
Array
(
[0] => 1
[1] => 2
[2] => 16
[3] => 18
[4] => 17
[5] => 14
[6] => 15
)
how about some recursion
$result = array();
function walkthrough($arr){
$keys = array_keys($arr);
array_push($result, $keys);
foreach ($keys as $key)
{
if (is_array($arr[$key]))
walkthrough($arr[$key]);
else
array_push($result,$arr[$key]);
}
return $result;
}
walkthrouth($your_arr);
P.S.:Code can be bugged, but you've got an idea :)
function flattenArray($array) {
$arrayValues = array();
foreach (new RecursiveIteratorIterator( new RecursiveArrayIterator($array)) as $val) {
$arrayValues[] = $val;
}
return $arrayValues;
} // function flattenArrayIndexed()
If we consider the nested array as a tree structure, you can apply depth first traversal to convert it into a list. That is, into a single array you desire.
I have searched all similar questions and it seems there is no way without a recursion that would keep the keys order intact.
So I just went with classic recursion:
function getArrayKeysRecursive(array $theArray)
{
$aArrayKeys = array();
foreach ($theArray as $k=>$v) {
if (is_array($v)) {
$aArrayKeys = array_merge($aArrayKeys, array($k), getArrayKeysRecursive($v));
} else {
$aArrayKeys = array_merge($aArrayKeys, array($k));
}
}
return $aArrayKeys;
}

PHP: Turning multidimensional arrays to single dimension arrays

Basically my app is interacting with a web service that sends back a weird multidimensional array such as:
Array
(
[0] => Array
(
[Price] => 1
)
[1] => Array
(
[Size] => 7
)
[2] => Array
(
[Type] => 2
)
)
That's not a problem, but the problem is that the service keeps changing the index of those items, so in the next array the Price could be at 1 instead of 0.
How do I effeciently transform arrays like this into a single dimension array so I can access the variables through $var['Size'] instead of $var[1]['Size']?
Appreciate your help
$result = call_user_func_array('array_merge', $array);
Like this:
$result = array();
foreach($array as $inner) {
$result[key($inner)] = current($inner);
}
The $result array would now look like this:
Array
(
[Price] => 1
[Size] => 7
[Type] => 2
)
I am using laravel's helper: http://laravel.com/api/source-function-array_flatten.html#179-192
function array_flatten($array)
{
$return = array();
array_walk_recursive($array, function($x) use (&$return) { $return[] = $x; });
return $return;
}
function flattenArray($input, $maxdepth = NULL, $depth = 0)
{
if(!is_array($input)){
return $input;
}
$depth++;
$array = array();
foreach($input as $key=>$value){
if(($depth <= $maxdepth or is_null($maxdepth)) && is_array($value)){
$array = array_merge($array, flattenArray($value, $maxdepth, $depth));
} else {
array_push($array, $value);
// or $array[$key] = $value;
}
}
return $array;
}
Consider $mArray as multidimensional array and $sArray as single dimensional array this code will ignore the parent array
function flatten_array($mArray) {
$sArray = array();
foreach ($mArray as $row) {
if ( !(is_array($row)) ) {
if($sArray[] = $row){
}
} else {
$sArray = array_merge($sArray,flatten_array($row));
}
}
return $sArray;
}
I think i found best solution to this : array_walk_recursive($yourOLDmultidimarray, function ($item, $key) {
//echo "$key holds $item\n";
$yourNEWarray[]=$item;
});
If you use php >= 5.6, you may use array unpacking (it's much faster):
$result = array_merge(...$array);
See wiki.php.net on unpacking

Categories