I am using this function two merge recursively arrays:
function array_merge_recursive_distinct(array &$array1, array &$array2) {
$merged = $array1;
foreach($array2 as $key => &$value) {
if(is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = array_merge_recursive_distinct($merged[$key], $value);
} else {
$merged[$key] = $value;
}
}
return $merged;
}
For using this function I am doing the following steps:
Declare an empty array $outArray = array();
Doing a while loop where I collect the information I need
During the while loop I call the array_merge_recursive_distinct function to fill the empty array recursively
However the final array contains only the last information it was gathered during the last while loop. I have tried to find a solution but I haven't succeed until now. What Am I doing wrong?
The recursive function takes all the info during the while loops (I have printed the input arrays in the recursive function) but it seems like it overwrites the merged array over and over again.
Thanks
CakePHP have a nice class called Hash, it implements a method called merge() who does exactly what you need
/**
* This function can be thought of as a hybrid between PHP's `array_merge` and `array_merge_recursive`.
*
* The difference between this method and the built-in ones, is that if an array key contains another array, then
* Hash::merge() will behave in a recursive fashion (unlike `array_merge`). But it will not act recursively for
* keys that contain scalar values (unlike `array_merge_recursive`).
*
* Note: This function will work with an unlimited amount of arguments and typecasts non-array parameters into arrays.
*
* #param array $data Array to be merged
* #param mixed $merge Array to merge with. The argument and all trailing arguments will be array cast when merged
* #return array Merged array
* #link http://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::merge
*/
function merge_arrays_recursivelly(array $data, $merge) { // I changed the function name from merge to merge_arrays_recursivelly
$args = array_slice(func_get_args(), 1);
$return = $data;
foreach ($args as &$curArg) {
$stack[] = array((array) $curArg, &$return);
}
unset($curArg);
while (!empty($stack)) {
foreach ($stack as $curKey => &$curMerge) {
foreach ($curMerge[0] as $key => &$val) {
if (!empty($curMerge[1][$key]) && (array) $curMerge[1][$key] === $curMerge[1][$key] && (array) $val === $val) {
$stack[] = array(&$val, &$curMerge[1][$key]);
} elseif ((int) $key === $key && isset($curMerge[1][$key])) {
$curMerge[1][] = $val;
} else {
$curMerge[1][$key] = $val;
}
}
unset($stack[$curKey]);
}
unset($curMerge);
}
return $return;
}
https://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::merge
Hash::merge source code
Perhaps something like this might be handy.
function array_merge_recursive_distinct(array &$array1, array &$array2) {
$merged = array_merge($array1,$array2);
asort($merged);
$merged = array_values(array_unique($merged));
return $merged;
}
$array1 = [];
$array2 = [1,2,3,4,5];
print_r(array_merge_recursive_distinct($array1,$array2));
$array1 = [1,2,3,6,12,19];
$array2 = [1,2,3,4,5];
print_r(array_merge_recursive_distinct($array1,$array2));
// output
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 12
[7] => 19
)
Test it on PHP Sandbox
Related
I am checking array values empty or not like following:
Long format:
$empty = array();
foreach($array as $value)
if(empty($value)) $empty[] = $value;
Expected Function:
$empty = array_empty_values($array);
Is there any function like array_empty_values() that find empty array indexes?
If you want to check and remove the empty array element you can check this function in php array_filter()
array_filter accepts an array as input and removes all elements which are equal to null / 0 / flase
Use array_filter php built-in function
function filter_empty($var) {
return empty($var);
}
$result_array = array_filter($your_array, "filter_empty");
$your_array = array(1,'2','3',false,'');
$result_array = array_filter($your_array, "filter_empty");
echo print_r($result_array, true);
will print
Array
(
[3] =>
[4] =>
)
If you need only indexes you can use array_keys built-in function
echo print_r(array_keys($result_array), true);
that will print
Array
(
[0] => 3
[1] => 4
)
You need an array with the keys, not with the values. because the values are empty.
/**
* Get keys of empty array values
* #param array $array The array to check.
* #return array The keys of the empty values.
*/
array_empty_values($array) {
$empty = array();
foreach($array as $key => $value) {
if(empty($value)) {
$empty[] = $key;
}
}
return $empty;
}
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;
}
Hope everyone is doing well...
I am looking for something similar to array_chunk() but using an empty value as the separator?
I have -
Array
(
[0] => /some/path:
[1] => file.csv
[2] => file.dat
[3] =>
[4] => /some/other/path:
[5] => file.csv
[6] => file.csv.gz
[7] => file.dat
[8] =>
[9] => /some/other/other/path:
[10] => file.csv
[11] => file.dat
)
And would like to achieve -
Array
(
[0] => Array
(
[0] => /some/path:
[1] => file.csv
[2] => file.dat
)
[1] => Array
(
[0] => /some/other/path:
[1] => file.csv
[2] => file.csv.gz
[3] => file.dat
)
[2] => Array
(
[0] => /some/other/other/path:
[1] => file.csv
[2] => file.dat
)
)
Now I cant just chunk on every 3 as you can see some locations will have more than 1 file.
I can achieve via loop and counter but I figured there would be a cleaner method?
Thanks
Best way I can think of is this loop which I think is pretty clean:
/**
* #param array $inputArr The array you wish to split.
* #param string $splitStr The string you wish to split by.
*
* #return array
*/
function split_arrays($inputArr, $splitStr) {
$outputArr = array();
$i = 0;
foreach ($inputArr as $data) {
if ($data == $splitStr) {
$i++;
continue;
}
$outputArr[$i][] = $data;
}
return $outputArr;
}
The other way I thought of also uses loops but is not as clean. It searches for the index of the next split string and breaks off that chunk.
/**
* #param array $inputArr The array you wish to split.
* #param string $splitStr The string you wish to split by.
*
* #return array
*/
function split_arrays2($inputArr,$splitStr) {
$outputArr = array(); $i=0;
while(count($inputArr)) {
$index = array_search($splitStr,$inputArr)
if($index === false) $index = count($inputArr);
$outputArr[$i++] = array_slice($inputArr,0,$index);
$inputArr = array_slice($inputArr,$index+1);
}
return $outputArr;
}
If and only if you are using a string for the split string which is not ever going to show up inside the middle of the other strings (space may or may not be the case for this) then I agree with the others that implode and explode are much simpler. In your case:
/**
* #param array $inputArr The array you wish to split.
* #param string $splitStr The string you wish to split by.
*
* #return array
*/
function split_arrays3($inputArr,$splitStr) {
$outputArr = array(); $i=0;
$str = implode("|",$inputArr);
$arr = explode("|$splitStr|");
foreach($arr as $i=>$string)
$outputArr[$i] = explode("|",$string);
return $outputArr;
}
$res = array();
foreach(explode("\n\n", implode("\n", $arr)) as $k => $v) {
$res[$k] = explode("\n", $v);
}
$res will contains the array you want.
Do you have two characters that will not occur in the array string for sure?
If so, suppose they are # and ;
We'll use combination of implode and explode
Then:
$arrstring = implode(';',$old_array); // Split via ; spearators
$arrstring = str_replace(';;','#',$arrstring); // If two ;; then mark end of array as #
$new_pre_array = explode('#',$arrstring); // Outer array
// Inner array
foreach($new_pre_array as $key => $entry) {
$temp_sub_array = explode(';',$entry);
$new_pre_array[$key] = $temp_sub_array;
}
return $new_pre_array;
Reference:
http://php.net/manual/en/function.explode.php
http://php.net/manual/en/function.implode.php
$chunked = chunkArray($your_array);
function chunkArray($array){
$return = array();
$index = 0;
foreach($array as $ar){
if($ar == "" or $ar == null){
$index++;
}
else{
$return[$index][] = $ar;
}
}
return $return;
}
I was opting to first locate at which places the array $array has to be splitted:
$splitAt = array_keys($array, '', TRUE);
This actually is the most magic. The array_splice function then can be used to get the chunks from the input array, only a temporary variable, I named it $last:
$last = 0;
is used to keep track because the length is not the position. Those $splitAt are then used to be inserted into the
$result = array();
$result array:
foreach($splitAt as $pos) {
$result[] = array_splice($array, 0, $pos - $last);
unset($array[0]);
$last += $pos + 1;
}
The leftover chunk from the array is then added as last element:
$result[] = $array;
And that's it. The full Example (Demo):
/**
* explode array by delimiter
*
* #param mixed $delimiter
* #param array $array
* #return array
*/
function array_explode($delimiter, array $array)
{
$splitAt = array_keys($array, $delimiter, TRUE);
$last = 0;
$result = array();
foreach ($splitAt as $pos) {
$result[] = array_splice($array, 0, $pos - $last);
$array && unset($array[0]);
$last += $pos + 1;
}
$result[] = $array;
return $result;
}
# Usage:
var_dump(array_explode('', $array));
I named the function array_explode because it works like explode on strings but for arrays.
The second option I see (and which might be preferrable) is to loop over the array and process it according to it's value: Either add to the current element or add the current to it:
/**
* explode array by delimiter
*
* #param mixed $delimiter
* #param array $array
* #return array
*/
function array_explode($delimiter, array $array)
{
$result[] = &$current;
foreach($array as $value) {
if ($value === $delimiter) {
unset($current);
$result[] = &$current;
continue;
}
$current[] = $value;
}
return $result;
}
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;
}
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