I am trying to build a function that allows me to find my way through a complex hierarchical structure.
For example, given this array:
$arr=array("name"=>"NameA","children"=>array());
$arr["children"][]=array("name"=>"NameB","size"=>"38");
$arr["children"][]=array("name"=>"NameC","children"=>array("name"=>'NameD',"children"=>array()));
I would like to find the complete key path to a given name. For example, a search for NameC would return $a=array('children',1) and NameD would return $a=array('children',1,'children'). This would allow me to retrieve NameD with $arr['children'][1]['children']['name'] or $arr[$a[0]][$a[1]][$a[2]]['name'].
I've experimented with calls to this function at each level:
function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
But recursive_array_search('NameC') returns 'children' instead of returning 1. I've tried modifying this in multiple ways, but to no avail.
Note that I can't change the structure of the original array because I'm using this to build a JSON array that needs to have this structure.
Any help would be appreciated.
I gather path in array
function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
// found - create array and put lower key
if($needle===$value) return(array($key));
if (is_array($value) && ($ret = recursive_array_search($needle,$value)) !== false)
// add current key as 1st item in array
{ array_unshift($ret, $key); return $ret; }
}
return false;
}
So, recursive_array_search('NameD',$arr) return:
Array (
[0] => children
[1] => 1
[2] => children
[3] => name
)
Related
I have an array of objects. I need to loop over these objects (preferably without foreach(), and if a certain key in the objects is not empty, then return true, otherwise return false.
For example,
$items = array(
'0' => stdClass {
name => Ryan
suppliers => array()
}
'1' => stdClass {
name => Dave
suppliers => array(
'0' => stdClass {}
)
}
)
Essentially, I need to go through the array and check the "supplier" key of the object, and if any of them are not empty, return true for the entire thing, otherwise return false.
What's wrong with foreach?
$check = function($arr) {
foreach($arr as $o) {
if (!empty($o->suppliers)) return true;
}
return false;
};
If you want to use it only in one place, use anonymous function
I don't understand why you don't want to use foreach because thing is - foreach is only right way because you leave loop as soon as you find value
One other option, reduce the array to a boolean.
array_reduce($items, function($hasSupplier, $item) {
return !empty($item->suppliers) || $hasSupplier;
});
Still, I prefer the foreach solution since it won't continue to iterate unnecessarily.
You can filter and check for a result:
if(array_filter($items, function($v) { return !empty($v->suppliers); })) {
//at least one not empty
} else {
//all are empty
}
If you really want a boolean:
$result = (bool)array_filter($items, function($v) { return !empty($v->suppliers); })
I have an array which consists of arrays. So, now suppose I want to retrieve the sku and price whose
key value is 2=>5 and 3=>7 so it should return price=>13 and sku=>bc i.e. that array whose index is at 1 in the array.
Hi I would probably try the following (Same as Riziers comment)
foreach($array as $key => $item) {
if($item[2] == 5 && $item[3] == 7) {
// return price
return $item;
}
}
There is a function array_search, which does what you want but for simple values. You can define your own function that will take not $needle, but callable predicate:
function array_search_callback(callable $predicate, array $array)
{
foreach ($array as $key => $item) {
if ($predicate($item)) {
return $key;
}
}
return false;
}
Having this function your example can be done like this:
$key = array_search_callback(function ($item) {
return $item[2] === '5' && $item[3] === '7';
}, $array);
$result = $key === false ? null : $array[$key];
I could simply return an item from the search function. But to be consistent with the original search function, I am returning the index.
As array_search_callback takes callable as an argument you can provide any criteria you want without the need of modifying the function itself.
Here is working demo.
The other day I asked a question related to this, and I got an answer, but it did not do what I wanted. Here is the method I have for traversing a multidimensional associative array, checking whether a key is in the array (from the answer to my previous question):
private function checkKeyIsInArray($dataItemName, $array)
{
foreach ($array as $key => $value)
{
// convert $key to string to prevent key type convertion
echo '<pre>The key: '.(string) $key.'</pre>';
if ((string)$key == $dataItemName)
return true;
if (is_array($value))
return $this->checkKeyIsInArray($dataItemName, $value);
}
return false;
}
Here is my array stucture:
Array (
[0] => Array ( [reset_time] => 2013-12-11 22:24:25 )
[1] => Array ( [email] => someone#example.com )
)
The method traverses the first array branch, but not the second. Could someone explain why this might be the case please? It seems I am missing something.
The problem is that you return whatever the recursive call returns, regardless of whether it succeeded or failed. You should only return if the key was found during the recursion, otherwise you should keep looping.
private function checkKeyIsInArray($dataItemName, $array)
{
foreach ($array as $key => $value)
{
// convert $key to string to prevent key type convertion
echo '<pre>The key: '.(string) $key.'</pre>';
if ((string)$key == $dataItemName)
return true;
if (is_array($value) && $this->checkKeyIsInArray($dataItemName, $value))
return true;
}
return false;
}
BTW, why is this a non-static function? It doesn't seem to need any instance properties.
Let's suppose I have below nested/multi-dim array:
array(
'World'=>array(
'Asia'=>array(
'Japan'=>array(
'City'=>'Tokyo'
)
)
)
);
I want to be able to find out all the parents in the heriarchy of current city.
For example, for the City, the response should be an array of parents containing:
array(
'World'=>array(
'Asia'=>array(
'Japan'
)
)
);
So how do I find all the parents in the chain in a nested array?
Recursion is your friend here. You need to traverse the array recursively and get all the parents. Your problem is discussed here, take a look at this comment.
<?php
function getParentStack($child, $stack) {
foreach ($stack as $k => $v) {
if (is_array($v)) {
// If the current element of the array is an array, recurse it and capture the return
$return = getParentStack($child, $v);
// If the return is an array, stack it and return it
if (is_array($return)) {
return array($k => $return);
}
} else {
// Since we are not on an array, compare directly
if ($v == $child) {
// And if we match, stack it and return it
return array($k => $child);
}
}
}
// Return false since there was nothing found
return false;
}
?>
I have an array within an array.
$a = array ( 0 => array ( 'value' => 'America', ), 1 => array ( 'value' => 'England', ), )
How do I check if 'America' exists in the array? The America array could be any key, and there could be any number of subarrays, so a generalized solution please.
Looking on the php manual I see in_array, but that only works for the top layer. so something like in_array("America", $a) would not work.
Thanks.
A general solution would be:
function deep_in_array($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && deep_in_array($needle, $element))
return true;
}
return false;
}
The reason why I chose to use in_array and a loop is: Before I examine deeper levels of the array structure, I make sure, that the searched value is not in the current level. This way, I hope the code to be faster than doing some kind of depth-first search method.
Of course if your array is always 2 dimensional and you only want to search in this kind of arrays, then this is faster:
function in_2d_array($needle, $haystack) {
foreach($haystack as $element) {
if(in_array($needle, $element))
return true;
}
return false;
}
PHP doesn't have a native array_search_recursive() function, but you can define one:
function array_search_recursive($needle, $haystack) {
foreach ($haystack as $value) {
if (is_array($value) && array_search_recursive($needle, $value)) return true;
else if ($value == $needle) return true;
}
return false;
}
Untested but you get the idea.
in_array("America", array_column($a, 'value'))
function search($a,$searchval){ //$a - array; $searchval - search value;
if(is_array($a)) {
foreach($a as $val){
if(is_array($val))
if(in_array($searchval,$val)) return true;
}
}
else return false;
}
search($a, 'America'); //function call