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.
Related
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.
Is it possible to create multidimensional array with its keys defined in array? Yes, it is, according to bunch of Stack Overflow answers. Here is one: Dynamic array keys
function insert_using_keys($arr, array $path, $value) { // See linked answer }
$arr = create_multi_array($arr, array('a', 'b', 'c'), 'yay'));
print_r($arr);
Prints
Array ( [a] => Array ( [b] => Array ( [c] => yay ) ) )
Would the same be possible for class properties?
This is a barebone version of my Collection class. Method set_at should add a multidimensional array to $data property the same way insert_using_keys function does.
class A {
protected $data = array();
public function set($key, $value) {
$this->data[$key] = $value;
}
public function set_at(array $keys, $value) {
}
}
I've tried a several modifications of the insert_using_keys to no avail. I was able to set the keys to the property, but not assign value "to the last one".
Would someone point me in the right direction please? Thanks in advance!
In the midst of recreating the "key-setter" function, I was able to answer my own question (was it your intention all along, Stefan?).
Here is the code:
public function set_at(array $keys, $value) {
$first_key = array_shift($keys);
foreach (array_reverse($keys) as $key) {
$value = array($key => $value);
}
$this->data[$first_key] = $value;
}
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
)
I have a method to check whether a key is in a nested associative array:
private function checkKeyIsInArray($dataItemName, $array) {
foreach ($array as $key=>$value) {
if ($key == $dataItemName) return true;
if (is_array($value)) {
checkKeyIsInArray($dataItemName, $value);
}
}
return false;
}
It always returns true, regardless of the keys I include or do not include. Here is my test array:
Array
(
[0] => Array ( [reset_time] => 2013-12-11 22:24:25 )
[1] => Array ( [email] => someone#example.com )
)
Please, what am I doing wrong? If I search for "reset_time" the method returns true (as I expect); when I search for "reset_expired" the method also returns true (which is incorrect).
Your method is almost works. But there is few issues.
Comparsion numeric values and strings. In first round method has 0 as key and 'email' as value. 0 == 'email' always returns true.
You should use $this when calling object member function.
You should return value of recursive function.
Your rewrited method.
class check
{
private function checkKeyIsInArray($dataItemName, $array)
{
foreach ($array as $key => $value)
{
// convert $key to string to prevent key type convertion
if ((string) $key == $dataItemName)
return true;
if (is_array($value))
// $this added
// return added
return $this->checkKeyIsInArray($dataItemName, $value);
}
return false;
}
public function myCheck($dataItemName, $array)
{
return $this->checkKeyIsInArray($dataItemName, $array);
}
}
$check = new check();
$array = array(array('reset_time' => 123, 'email' => 123));
var_dump($check->myCheck('reset_time', $array)); // true
var_dump($check->myCheck('reset_expired', $array)); // false
var_dump($check->myCheck('0', $array)); // true
I have updated your own code, there was some minor issue.please check.
function checkKeyIsInArray($dataItemName, $array) {
foreach ($array as $key=>$value) {
## here $key is int and $dataItemName is string so its alway comes true in ur case
if ("$key" == $dataItemName) {
return true;
}
else if (is_array($value)) {
$returnvalue=checkKeyIsInArray($dataItemName, $value);
## once a matching key found stop further recursive call
if($returnvalue==true){
return true;
}
}
}
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