PHP : flatten array - fastest way? [duplicate] - php

This question already has answers here:
How to Flatten a Multidimensional Array?
(31 answers)
Closed 5 months ago.
Is there any fast way to flatten an array and select subkeys ('key'&'value' in this case) without running a foreach loop, or is the foreach always the fastest way?
Array
(
[0] => Array
(
[key] => string
[value] => a simple string
[cas] => 0
)
[1] => Array
(
[key] => int
[value] => 99
[cas] => 0
)
[2] => Array
(
[key] => array
[value] => Array
(
[0] => 11
[1] => 12
)
[cas] => 0
)
)
To:
Array
(
[int] => 99
[string] => a simple string
[array] => Array
(
[0] => 11
[1] => 12
)
)

Give this a shot:
$ret = array();
while ($el = each($array)) {
$ret[$el['value']['key']] = $el['value']['value'];
}

call_user_func_array("array_merge", $subarrays) can be used to "flatten" nested arrays.
What you want is something entirely different. You could use array_walk() with a callback instead to extract the data into the desired format. But no, the foreach loop is still faster. There's no array_* method to achieve your structure otherwise.

Hopefully it will help someone else, but here is a function I use to flatten arrays and make nested elements more accessible.
Usage and description here:
https://totaldev.com/flatten-multidimensional-arrays-php/
The function:
// Flatten an array of data with full-path string keys
function flat($array, $separator = '|', $prefix = '', $flattenNumericKeys = false) {
$result = [];
foreach($array as $key => $value) {
$new_key = $prefix . (empty($prefix) ? '' : $separator) . $key;
// Make sure value isn't empty
if(is_array($value)) {
if(empty($value)) $value = null;
else if(count($value) == 1 && isset($value[0]) && is_string($value[0]) && empty(trim($value[0]))) $value = null;
}
$hasStringKeys = is_array($value) && count(array_filter(array_keys($value), 'is_string')) > 0;
if(is_array($value) && ($hasStringKeys || $flattenNumericKeys)) $result = array_merge($result, flat($value, $separator, $new_key, $flattenNumericKeys));
else $result[$new_key] = $value;
}
return $result;
}

This should properly combine arrays with integer keys. If the keys are contiguous and start at zero, they will be dropped. If an integer key doesn't yet exist in the flat array, it will be kept as-is; this should mostly preserve non-contiguous arrays.
function array_flatten(/* ... */)
{
$flat = array();
array_walk_recursive(func_get_args(), function($value, $key)
{
if (array_key_exists($key, $flat))
{
if (is_int($key))
{
$flat[] = $value;
}
}
else
{
$flat[$key] = $value;
}
});
return $flat;
}
You could use !isset($key) or empty($key) instead to favor useful values.
Here's a more concise version:
function array_flatten(/* ... */)
{
$flat = array();
array_walk_recursive(func_get_args(), function($value, $key) use (&$flat)
{
$flat = array_merge($flat, array($key => $value));
});
return $flat;
}

Related

How can I call particular array value of array in php?

I'm getting below output as an array.
$array =
Array
(
[12] => Array
(
[1] => Array
(
[14] => Array
(
[0] => Array
(
[name] => Avaya Implementation Services
[service_id] => 14
[ser_type_id] => 1
[service_desc] =>Avaya Implementation Servic
)
)
)
)
);
I want to print only service_desc array value. and I don't want call like $array[12][1][14][0]['service_desc'];
How can I call particular service_desc array value of the array?
As you mentioned that you don't want to call it as $array[12][1][14][0]['service_desc'] you can use extract function which will create variables from your array,
extract($array[12][1][14][0]);
echo $service_desc;
And then you can use your particular key such as service_desc as variable.
You can try this function: (Please optimize as per your requirements)
$arr ="<YOUR ARRAY>";
$val = "service_desc";
echo removekey($arr, $val);
function removekey($arr, $val) {
$return = array();
foreach ($arr as $k => $v) {
if (is_array($v) && $k !== $val) {
removekey($v, $val);
continue;
}
if ($k == $val) {
echo ($arr[$k]);
die;
}
$return[$k] = $v;
}
return $return;
}
You can use array_walk_rescursive to frame a single dimensional array of matching keys:
DEMO
<?php
$array[12][1][14][0]['service_desc'] = 'Avaya Implementation Servic';
$array[12][1][14][0]['service'] = 'dsfasf';
$array[12][1][114][0]['service_desc'] = 'Avaya Implementation Servicasdfdsf';
$searchKey = 'service_desc';
$desiredValues = [];
array_walk_recursive($array, function ($v, $k) use ($searchKey, &$desiredValues) {
if ($k === $searchKey) {
$desiredValues[] = $v;
}
});
print_r($desiredValues);
So this will yield:
Array
(
[0] => Avaya Implementation Servic
[1] => Avaya Implementation Servicasdfdsf
)
You might use the array_walk_recursive function.
array_walk_recursive($array, function ($val, $key) {
if ($key == 'service_desc') print_r($val);
} );
Instead of the print_r statement, you can collect your data into another structure, which you convey using the use statement, or with the $userdata additional parameter (see http://www.php.net/manual/en/function.array-walk-recursive.php ).
$results = array();
array_walk_recursive($array, function ($val, $key) use (&$results) {
if ($key == 'service_desc') {
$results []= $val;
}
} );
Pay extra care to the & in front of the use (&$results) otherwise your array of results will be considered immutable inside the callback (i.e. all changes discarded).
Convert multidimensional array to single array using iterator_to_array
REF: http://php.net/manual/en/function.iterator-to-array.php
$service_desc= iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($your_array)), 0);
print_r($service_desc);
Result:
Array
(
[name] => Avaya Implementation Services
[service_id] => 14
[ser_type_id] => 1
[service_desc] =>Avaya Implementation Servic
)

Php Get the key of a array based in a string [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to search by key=>value in a multidimensional array in PHP
PHP search for Key in multidimensional array
How can I search in a array values and get the key?
Example:
search for id 1 = key 0
or
search for name Frank = key 1
Array
(
[0] => Array
(
[id] => 1
[name] => Bob
[url] => http://www.bob.com.br
)
[1] => Array
(
[id] => 2
[name] => Frank
[url] => http://www.frank.com.br
)
)
Thks.
Adriano
Use array_search
foreach($array as $value) {
$result = array_search('Frank', $value);
if($result !== false) break;
}
echo $result
If you do not know the depth, you can do something like the following, which employs the use of RecursiveIteratorIterator and RecursiveArrayIterator:
<?php
/*******************************
* array_multi_search
*
* #array array to be searched
* #input search string
*
* #return array(s) that match
******************************/
function array_multi_search($array, $input){
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach($iterator as $id => $sub){
$subArray = $iterator->getSubIterator();
if(#strstr(strtolower($sub), strtolower($input))){
$subArray = iterator_to_array($subArray);
$outputArray[] = array_merge($subArray, array('Matched' => $id));
}
}
return $outputArray;
}
don't think there is a predifned function for that,
but here is one:
function sub_array_search($array, $sub_key, $value, $strict = FALSE)
{
foreach($array as $key => $sub_array)
{
if($sub_array[$sub_key] == $value)
{
if(!$strict OR $sub_array[$sub_key] === $value)
{
return $key;
}
}
}
return FALSE;
}

How do I invert a multi-dimensional array?

I have an array with n elements in it, with each element containing n child elements, each containing...
Array
(
[tea] => Array
(
[drink] => Array
(
[food] =>
)
)
[biscuits] => Array
(
[snack] => Array
(
[food] =>
)
)
...
)
What I want to do is have the inner most element on the outside, and the outer most elements on the inside:
Array
(
[food] => Array
(
[drink] => Array
(
[tea] =>
)
[snack] => Array
)
[biscuits] =>
(
)
...
)
And the solution needs to be able to deal with n children arrays. I am aware of How do I invert a multidimensional array in PHP but the solutions there did not solve this problem.
I'm pretty sure this could be condensed further, but it does the job:
function flatten(array $array) {
$key = array(key($array));
$val = current($array);
if (is_array($val)) {
$key = array_merge(flatten($val), $key);
}
return $key;
}
function build(array $path, array $result) {
$key = array_shift($path);
if (!isset($result[$key])) {
$result[$key] = $path ? array() : null;
}
if ($path) {
$result[$key] = build($path, $result[$key]);
}
return $result;
}
$result = array();
foreach ($array as $key => $value) {
$result = build(flatten(array($key => $value)), $result);
}
Demo: http://codepad.org/rnZPdWGG

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