i have built some functions which do this sort of thing.
i'll share them with you..
function walkArray (&$a, $keyCallback=null, $valueCallback=null, $callKeyForValues=false, $callbackParams=null, $k='', $level=0, $path='') {
// usage : walkArray ($someRecursiveArray, 'walkArray_printKey', 'walkArray_printValue');
// can handle recursive arrays. a nested array is a recursive array.
// is faster, especially on large arrays, than RecuriveArrayIterator, see speed testing comment at http://php.net/manual/en/class.recursiveiteratoriterator.php
// provides detailed information to callbacks on where in the data we are, something that array_walk_recursive just doesnt do.
// passes data around as pointers, not copies of data.
if (!is_array($a)) {
return badResult (E_USER_ERROR, array (
'msg' => 'walkArray() was called but $a parameter passed is not an array.'
));
} else {
foreach ($a as $k=>&$v) {
$cd = array ( // callback data
'type' => 'key',
'path' => $path,
'level' => $level,
'k' => &$k,
'v' => &$v,
'params' => &$callbackParams
);
if (!is_null($keyCallback) && ($callKeyForValues || is_array($v))) call_user_func ($keyCallback, $cd);
if (is_array ($v)) {
walkArray ($a[$k], $keyCallback, $valueCallback, $callKeyForValues, $callbackParams, $k, $level+1, $path.'/'.$k);
} else {
$cd['type'] = 'value';
if (!is_null($valueCallback)) call_user_func ($valueCallback, $cd);
}
}
}
$r = true;
return goodResult($r);
}
function walkArray_printKey ($cd) {
echo '<div style="background:blue;color:yellow;border-radius:5px;padding:2px;margin-top:5px;">'.PHP_EOL;
$indent = 20 * $cd['level'];
echo '<div style="padding-left:'.$indent.'px">'.PHP_EOL;
echo 'key : '.$cd['k'].'<br/>'.PHP_EOL;
echo 'path : '.$cd['path'].'<br/>'.PHP_EOL;
echo '</div>'.PHP_EOL;
echo '</div>'.PHP_EOL;
}
function walkArray_printValue ($cd) {
echo '<pre style="background:green;color:white;border-radius:5px;padding:2px;margin-top:2px;">'.PHP_EOL;
$indent = 20 * $cd['level'];
echo '<div style="padding-left:'.$indent.'px">'.PHP_EOL;
echo 'key : '.$cd['k'].'<br/>'.PHP_EOL;
echo 'path : '.$cd['path'].'<br/>'.PHP_EOL;
echo 'value : '.$cd['v'].'<br/>'.PHP_EOL;
echo '</div>'.PHP_EOL;
echo '</pre>'.PHP_EOL;
}
function &chaseToPath (&$wm, $path, $create=false) {
//var_dump ($create); die();
//echo '$wm=<pre>'; var_dump ($wm);echo '</pre>'; //die();
//$path = str_replace ('/', '/d/', $path);
//$path .= '/d';
$nodes = explode ('/', $path);
foreach ($nodes as $idx=>$node) {
if (is_numeric($node) && is_string($node)) {
if (strpos($node,'.')===false) {
$nodes[$idx] = (int)$node;
} else {
$nodes[$idx] = (float)$node;
}
}
}
$chase = &chase ($wm, $nodes, $create);
//echo '$wm=<pre>'; var_dump ($wm);echo '</pre>'; die();
/*
$dbg = array (
'$path' => $path,
'$nodes' => $nodes,
'$wm' => $wm,
'$chase' => $chase
);
echo '$dbg=<pre style="background:red;color:yellow;">'; var_dump ($dbg); echo '</pre>';
*/
//die();
$false = false;
if (good($chase)) {
$arr = &result($chase);
return $arr;
} else return $false;
}
function &chase (&$arr, $indexes, $create=false) {
if (false) {
echo 'sitewide/functions.php --- $arr=<pre>'; var_dump ($arr); echo '</pre>';
echo 'sitewide/functions.php --- $indexes=<pre>'; var_dump ($indexes); echo '</pre>';
echo 'sitewide/functions.php --- $create=<pre>'; var_dump ($create); echo '</pre>';
}
$r = &$arr;
foreach ($indexes as $idx) {
//echo 'sitewide/functions.php --- $idx=<pre>'; var_dump ($idx); var_dump (array_key_exists($idx,$r)); var_dump ($r); echo '</pre>';
if (
is_array($r)
&& (
$create===true
|| array_key_exists($idx,$r)
)
) {
if ($create===true && !array_key_exists($idx,$r)) $r[$idx]=array();
//echo 'sitewide/functions.php --- $idx=<pre>'; var_dump ($idx); echo '</pre>';
$r = &$r[$idx];
} else {
/*
$err = array(
'msg' => 'Could not walk the full tree',
'vars' => array(
'$idx--error'=>$idx,
'$indexes'=>$indexes,
'$arr'=>$arr
)
);
badResult (E_USER_NOTICE, $err);
*/
$ret = false; // BUG #2 squashed
return $ret;
}
}
//echo 'sitewide/functions.php --- $r=<pre>'; var_dump ($r); echo '</pre>';
return goodResult($r);
}
function &chaseToReference (&$array, $path) {
if (!empty($path)) {
if (empty($array[$path[0]])) {
$err = array(
'msg' => 'Could not walk the full tree',
'$path' => $path,
'$array (possibly partially walked)' => $array
);
return badResult (E_USER_NOTICE, $err);
} else return chaseToReference($array[$path[0]], array_slice($path, 1));
} else {
return goodResult($array);
}
}
function good($r) {
return (
is_array($r)
&& array_key_exists('result',$r)
);
}
function &result(&$r) {
return $r['result'];
}
function &resultArray (&$r) {
$r2 = array();
foreach ($r as $k => $v) {
$r2[$k] = result($v);
}
return $r2;
}
function &goodResult(&$r) {
$r2 = array (
'isMetaForFunc' => true,
'result' => &$r
);
return $r2;
}
// usage : walkArray ($someRecursiveArray, 'walkArray_printKey', 'walkArray_printValue');
// can handle recursive arrays. a nested array is a recursive array.
// is faster, especially on large arrays, than RecuriveArrayIterator, see speed testing comment at http://php.net/manual/en/class.recursiveiteratoriterator.php
// provides detailed information to callbacks on where in the data we are, something that array_walk_recursive just doesnt do.
// passes data around as pointers, not copies of data.
if (!is_array($a)) {
return badResult (E_USER_ERROR, array (
'msg' => 'walkArray() was called but $a parameter passed is not an array.'
));
} else {
foreach ($a as $k=>&$v) {
$cd = array ( // callback data
'type' => 'key',
'path' => $path,
'level' => $level,
'k' => &$k,
'v' => &$v,
'params' => &$callbackParams
);
if (!is_null($keyCallback) && ($callKeyForValues || is_array($v))) call_user_func ($keyCallback, $cd);
if (is_array ($v)) {
walkArray ($a[$k], $keyCallback, $valueCallback, $callKeyForValues, $callbackParams, $k, $level+1, $path.'/'.$k);
} else {
$cd['type'] = 'value';
if (!is_null($valueCallback)) call_user_func ($valueCallback, $cd);
}
}
}
$r = true;
return goodResult($r);
}
function walkArray_printKey ($cd) {
echo '<div style="background:blue;color:yellow;border-radius:5px;padding:2px;margin-top:5px;">'.PHP_EOL;
$indent = 20 * $cd['level'];
echo '<div style="padding-left:'.$indent.'px">'.PHP_EOL;
echo 'key : '.$cd['k'].'<br/>'.PHP_EOL;
echo 'path : '.$cd['path'].'<br/>'.PHP_EOL;
echo '</div>'.PHP_EOL;
echo '</div>'.PHP_EOL;
}
function walkArray_printValue ($cd) {
echo '<pre style="background:green;color:white;border-radius:5px;padding:2px;margin-top:2px;">'.PHP_EOL;
$indent = 20 * $cd['level'];
echo '<div style="padding-left:'.$indent.'px">'.PHP_EOL;
echo 'key : '.$cd['k'].'<br/>'.PHP_EOL;
echo 'path : '.$cd['path'].'<br/>'.PHP_EOL;
echo 'value : '.$cd['v'].'<br/>'.PHP_EOL;
echo '</div>'.PHP_EOL;
echo '</pre>'.PHP_EOL;
}
function &chaseToPath (&$wm, $path, $create=false) {
//var_dump ($create); die();
//echo '$wm=<pre>'; var_dump ($wm);echo '</pre>'; //die();
//$path = str_replace ('/', '/d/', $path);
//$path .= '/d';
$nodes = explode ('/', $path);
foreach ($nodes as $idx=>$node) {
if (is_numeric($node) && is_string($node)) {
if (strpos($node,'.')===false) {
$nodes[$idx] = (int)$node;
} else {
$nodes[$idx] = (float)$node;
}
}
}
$chase = &chase ($wm, $nodes, $create);
//echo '$wm=<pre>'; var_dump ($wm);echo '</pre>'; die();
/*
$dbg = array (
'$path' => $path,
'$nodes' => $nodes,
'$wm' => $wm,
'$chase' => $chase
);
echo '$dbg=<pre style="background:red;color:yellow;">'; var_dump ($dbg); echo '</pre>';
*/
//die();
$false = false;
if (good($chase)) {
$arr = &result($chase);
return $arr;
} else return $false;
}
function &chase (&$arr, $indexes, $create=false) {
if (false) {
echo 'sitewide/functions.php --- $arr=<pre>'; var_dump ($arr); echo '</pre>';
echo 'sitewide/functions.php --- $indexes=<pre>'; var_dump ($indexes); echo '</pre>';
echo 'sitewide/functions.php --- $create=<pre>'; var_dump ($create); echo '</pre>';
}
$r = &$arr;
foreach ($indexes as $idx) {
//echo 'sitewide/functions.php --- $idx=<pre>'; var_dump ($idx); var_dump (array_key_exists($idx,$r)); var_dump ($r); echo '</pre>';
if (
is_array($r)
&& (
$create===true
|| array_key_exists($idx,$r)
)
) {
if ($create===true && !array_key_exists($idx,$r)) $r[$idx]=array();
//echo 'sitewide/functions.php --- $idx=<pre>'; var_dump ($idx); echo '</pre>';
$r = &$r[$idx];
} else {
/*
$err = array(
'msg' => 'Could not walk the full tree',
'vars' => array(
'$idx--error'=>$idx,
'$indexes'=>$indexes,
'$arr'=>$arr
)
);
badResult (E_USER_NOTICE, $err);
*/
$ret = false; // BUG #2 squashed
return $ret;
}
}
//echo 'sitewide/functions.php --- $r=<pre>'; var_dump ($r); echo '</pre>';
return goodResult($r);
}
function &chaseToReference (&$array, $path) {
if (!empty($path)) {
if (empty($array[$path[0]])) {
$err = array(
'msg' => 'Could not walk the full tree',
'$path' => $path,
'$array (possibly partially walked)' => $array
);
return badResult (E_USER_NOTICE, $err);
} else return chaseToReference($array[$path[0]], array_slice($path, 1));
} else {
return goodResult($array);
}
}
function good($r) {
return (
is_array($r)
&& array_key_exists('result',$r)
);
}
function &result(&$r) {
return $r['result'];
}
function &resultArray (&$r) {
$r2 = array();
foreach ($r as $k => $v) {
$r2[$k] = result($v);
}
return $r2;
}
function &goodResult(&$r) {
$r2 = array (
'isMetaForFunc' => true,
'result' => &$r
);
return $r2;
}
On Thu, Feb 25, 2021 at 7:59 AM <gordonisnz@xxxxxxxxx> wrote:
Hello. I have a multidimensional array.
Some 'routes' only go 2-3 key/values down, While other options have
6-10 keys deep (Ive not planned this as yet - just started)..
In the below array (just random words) I'm 'at' the 'Ginger' option
now. I am wondering if there was a quick way of searching the array
for 'Ginger' and finding the path "up" the array to get the key 2
levels up.
So for this example i'll want to go 'up' 2 levels to get 'crackers'
(each unique key, will have a TITLE value, and a number of OPTIONS -
2-6 options each)
Is there a quick way of doing this ?
EXAMPLE array:-
(
[top] => Array
(
[CRUSH] => Array
(
[TITLE] => Crush
[OPTION1] => Array
(
[cheese] => Array
(
[TITLE] => Cheese option
)
)
[OPTION2] => Array
(
[crackers] => Array
(
[TITLE] => crackers
[OPTION1] => Array
(
[NAME] => crackers option 1
[Ginger] => Array
(
[TITLE] => Ginger title1
[TITLE2] => Ginger title2
)
)
[OPTION2] => crackers option 2
)
)
)
)
)
--
Gordon.