Passing Nested Keys to Custom Array Lookup Function, PHP - php

I have a custom array lookup function which I pass both array and key to and it returns the value if it finds it or an empty string. It has been working well as intended only to realize that I cannot pass a nested key to it. By nesting I mean key like [outer-key][inner-key]. The function (in a class) is:
public function getArrayValueSafely($dataArray, $dKey){
if(!is_array($dataArray) || count($dataArray) < 1){
return false;
}
if(strlen($dKey) < 1){
return false;
}
$retVal = '';
try {
$retVal = $dataArray[$dKey];
} catch (Exception $e) {
//echo 'Caught exception: ', $e->getMessage(), "\n";
}
return $retVal;
}
The warning is always:
Warning: Undefined array key "['SUBJECT_STRANDS']['RELIGION']"
Whether the keys is given as: ['SUBJECT_STRANDS']['RELIGION'] or [SUBJECT_STRANDS][RELIGION]; the keys are definitely existing.
Any pointers to solve this will be highly appreciated as I am currently forced to pull the data using outer-key, then do a second lookup using inner-key.
Sample call as requested by #chris-haas:
$currentKey = "['SUBJECT_STRANDS']['RELIGION']";
//$currentKey = "[SUBJECT_STRANDS][RELIGION]"; //tried this also
$currentStrands = $this->getArrayValueSafely($lastExamData, $currentKey);

You could maintain a reference of the current array, while iterating over the keys you want to traverse.
function getArrayValueSafely($dataArray, $keys)
{
$ref = &$dataArray; // Start with the given array
foreach ($keys as $key) { // loop over the keys
if (! isset($ref[$key])) { // key not found, return.
return false;
}
$ref = $ref[$key]; // move the pointer on sub array.
}
return $ref; // return reference value.
}
// Sample Data :
$lastExamData = ['SUBJECT_STRANDS' => ['RELIGION' => 'data']];
// Keys to traverse :
$currentKey = ['SUBJECT_STRANDS', 'RELIGION'];
// Get the value
$currentStrands = getArrayValueSafely($lastExamData, $currentKey);
var_dump($currentStrands); // string(4) "data"
live demo

Related

How to check in PHP that any values exist in array in addition to some fixed value

I have an array like this:
$array = array('static_value_1', 'static_value_2', 'extra_value_1', 'extra_value_2');
How could I return true if any value exists in array in addition to static_value_1 and/or static_value_2?
For example this array should return true:
array = array('static_value_1', 'static_value_2', 'extra_value_1');
and this one false:
array = array('static_value_1', 'static_value_2');
Thanks!
I think just looping looking for non-static should work:
function check_array($check) {
$static=Array('static_value_1', 'static_value_2');
// Dealing with empty array.
if(count($check)==0) return false;
foreach($check as $value) {
// If value is not in static collection is an addition...
if(!in_array($value, $static)) {
return false;
}
}
return true;
}

Recursive function with unknown depth of values. Return all values (undefined depth)

I have a question about a recursive PHP function.
I have an array of ID’s and a function, returning an array of „child id’s“ for the given id.
public function getChildId($id) {
…
//do some stuff in db
…
return childids;
}
One childid can have childids, too!
Now, I want to have an recursive function, collecting all the childids.
I have an array with ids like this:
$myIds = array("1111“,"2222“,"3333“,“4444“,…);
and a funktion:
function getAll($myIds) {
}
What I want: I want an array, containing all the id’s (including an unknown level of childids) on the same level of my array. As long as the getChildId($id)-function is returning ID’s…
I started with my function like this:
function getAll($myIds) {
$allIds = $myIds;
foreach($myIds as $mId) {
$childids = getChildId($mId);
foreach($childids as $sId) {
array_push($allIds, $sId);
//here is my problem.
//what do I have to do, to make this function rekursive to
//search for all the childids?
}
}
return $allIds;
}
I tried a lot of things, but nothing worked. Can you help me?
Assuming a flat array as in your example, you simply need to call a function that checks each array element to determine if its an array. If it is, the function calls it itself, if not the array element is appended to a result array. Here's an example:
$foo = array(1,2,3,
array(4,5,
array(6,7,
array(8,9,10)
)
),
11,12
);
$bar = array();
recurse($foo,$bar);
function recurse($a,&$bar){
foreach($a as $e){
if(is_array($e)){
recurse($e,$bar);
}else{
$bar[] = $e;
}
}
}
var_dump($bar);
DEMO
I think this code should do the trick
function getAll($myIds) {
$allIds = Array();
foreach($myIds as $mId) {
array_push($allIds, $mId);
$subids = getSubId($mId);
foreach($subids as $sId) {
$nestedIds = getAll($sId);
$allIds = array_merge($allIds, $nestedIds);
}
}
return $allIds;
}

Passing location in subarray as string

I have a function that searches a multidimensional array for a key, and returns the path
inside the array to my desired key as a string.
Is there any way I can use this string in php to reach this place in my original array, not to get to the value but to make changes to this specific bracnch of the array?
An example:
$array = array('first_level'=>array(
'second_level'=>array(
'desired_key'=>'value')));
in this example the function will return the string:
'first_level=>second_level=>desired_key'
Is there a way to use this output, or format it differently in order to use it in the following or a similar way?
$res = find_deep_key($array,'needle');
$array[$res]['newkey'] = 'injected value';
Thanks
If the keys path is safe (e.g. not given by the user), you can use eval and do something like:
$k = 'first_level=>second_level=>desired_key';
$k = explode('=>', $k);
$keys = '[\'' . implode('\'][\'', $k) . '\']';
eval('$key = &$array' . $keys . ';');
var_dump($key);
I think you want to do a recursive search in the array for your key? Correct me if i am wrong.
Try this
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;
}
Taken from here http://in3.php.net/manual/en/function.array-search.php#91365
You need something like:
find_key_in_array($key, $array, function($foundValue){
// do stuff here with found value, e.g.
return $foundValue * 2;
});
and the implementation would be something like:
function find_key_in_array($key, $array, $callback){
// iterate over array fields recursively till you find desired field, then:
...
$array[$key] = $callback($array[$key]);
}
If you need to append some new sub-array into multidimensional complex array and you know where exactly it should be appended (you have path as a string), this might work (another approach without eval()):
function append_to_subarray_by_path($newkey, $newvalue, $path, $pathDelimiter, &$array) {
$destinationArray = &$array;
foreach (explode($pathDelimiter, $path) as $key) {
if (isset($destinationArray[$key])) {
$destinationArray = &$destinationArray[$key];
} else {
$destinationArray[$newkey] = $newvalue;
}
}
}
$res = find_deep_key($array,'needle');
append_to_subarray_by_path('newkey', 'injected value', $res, '=>', $array);
Of course, it will work only if all keys in path already exist. Otherwise it will append new sub-array into wrong place.
just write a function that takes the string and the array. The function will take the key for each array level and then returns the found object.
such as:
void object FindArray(Array[] array,String key)
{
if(key.Length == 0) return array;
var currentKey = key.Split('=>')[0];
return FindArray(array[currentKey], key.Remove(currentKey));
}

How to Promote certain elements to the start of an array in PHP

If certain elements are contained in an array, I want them moved to the start of it.
At first I used a bunch of array_diff_keys to get it to work, but I wanted something more elegant. So I tried using uksort with a callback, but perhaps I'm doing it wrong because it's not working.
I tried this, it's a method of my helper class, but it's not working.
$good_elements = array('sku','name','type','category','larping');
$test_array = array('sku','name','asdf','bad_stuff','larping','kwoto');
$results = helper::arrayPromoteElementsIfExist($test_array,$good_elements,false);
public static function arrayPromoteElementsIfExist($test_array,$promote_elements,$use_keys = false) {
foreach(array('test_array','promote_elements') as $arg) {
if(!is_array($$arg)) {
debug::add('errors',__FILE__,__LINE__,__METHOD__,'Must be array names',$$arg);
return false;
}
}
if(!$use_keys) {
$test_array = array_flip($test_array); // compare keys
$promote_elements = array_flip($promote_elements); // compare keys
}
uksort($test_array,function($a,$b) use($promote_elements) {
$value1 = intval(in_array($a, $promote_elements));
$value2 = intval(in_array($b,$promote_elements));
return $value1 - $value2;
});
if(!$use_keys) {
$test_array = array_flip($test_array);
}
return $test_array;
}
Fairly quick and dirty but here you go.
function promoteMembers($input, $membersToPromote)
{
$diff = array_diff($input, $membersToPromote);
return array_merge($membersToPromote, $diff);
}
Assuming I understood what you wanted to do.
Example output: for your verification.

add/modify php n level associative array

$arrResult=array(
0=>array('categoryid'=>112,'catname'=>'apperal','subcategory'=>array(
412=>array('categoryid'=>428,'catname'=>'rainwear','subcategory'=>array(
428=>array('categoryid'=>413,'catname'=>'summer','subcategory'=>array()))))));
print_r($arrResult);
$iterator = new RecursiveArrayIterator($arrResult);
iterator_apply($iterator, 'traverseStructure', array($iterator));
function traverseStructure($iterator) {
$arrAddResult=array('categoryid'=>416,'catname'=>'winter','subcategory'=>array());
while ( $iterator -> valid() ) {
if ( $iterator -> hasChildren() ) {
traverseStructure($iterator -> getChildren());
}
else {
if($iterator -> current() == 413)
{
$arr=&$iterator;
$a='arr';
${$a}['subcategory']=$arrAddResult;
break;
}
}
$iterator -> next();
}
}
the expected output is to append the 'arrAddResult' appenedn in $arrResult. But with some reason the iterator get modify but it doesn't reflect the modification in arrResult array.
I tried passing the array by ref in function 'traverseStructure' but still struggling to get the correct output.
I am trying iterator first. I have to constructor a N-Level associative array as arrResult hence opt to use the iterator.
Here's an example on a way of doing this with one array.
<?php
$arrResult=array(
1=>array('categoryid'=>112,'catname'=>'apperal','subcategory'=>array()),
0=>array('categoryid'=>112,'catname'=>'apperal','subcategory'=>array(
1=>array('categoryid'=>112,'catname'=>'rainwear','subcategory'=>array(
1=>array('categoryid'=>112,'catname'=>'apperal','subcategory'=>array()),
428=>array('categoryid'=>413,'catname'=>'summer','subcategory'=>array()))
),
412=>array('categoryid'=>428,'catname'=>'rainwear','subcategory'=>array(
1=>array('categoryid'=>112,'catname'=>'apperal','subcategory'=>array()),
428=>array('categoryid'=>413,'catname'=>'summer','subcategory'=>array()))
)
)
)
);
function append(&$ar,$who,$what){
// just a simple check, you can remove it
if(!is_array($ar))return false;
// loop through all keys
foreach($ar as $k=>$v){
// found node, i'm assuming you don't have the node multiple times
// if you want this to go forever, remove the returns and the if on the add()
if($v['categoryid']==$who){
$ar[$k]['subcategory'][]=$what;
return true;
}
// recursion !
if(add($ar[$k]['subcategory'],$who,$what))return true;// if found stop
}
// key not found here in this node or subnodes
return false;
}
append($arrResult,413,array('categoryid'=>416,'catname'=>'winter','subcategory'=>array()));
echo'<pre>';
var_dump($arrResult);
This might be inefficient on large arrays. I'd recommend making a class that caches the $who and $what so it doesn't get copied to all the levels of the traversal. The rest should be identical.

Categories