有人可以帮我提供一些代码或说明,说明如何递归地走动数组并在到达最后一个元素时打印它的完整路径?一个简单的回显就可以了,因为我会将代码调整到我正在开发的其他一些功能。
该函数不需要计算数组维度,因为将传递此参数:
例:
$depth = 8;
$array[1][3][5][6][9][5][8][9];
当函数到达第 8 个元素时,它会打印它的所有路径:
//print path
'1 -> 3 -> 5 -> 6 -> 9 -> 5 -> 8 -> 9'
正如我所说,只有以这种格式打印才能工作,因为我会将代码实现到其他函数中。
数组键可以具有相同的值。显然,对于整个 arary,同一序列中的值不同。
更新:
步行递归函数:
$someArray[1][2][3] = 'end';
$someArray[1][2][6] = 'end';
$someArray[1][3][6] = 'end';
$someArray[4][3][7] = 'end';
function listArrayRecursive(&$array_name, $ident = 0){
if (is_array($array_name)){
foreach ($array_name as $k => &$v){
if (is_array($v)){
for ($i=0; $i < $ident * 10; $i++){ echo " "; }
echo $k . " : " . "<br>";
listArrayRecursive($v, $ident + 1);
}else{
for ($i=0; $i < $ident * 10; $i++){ echo " "; }
echo $k . " : " . $v . "<br>";
}
}
}else{
echo "Variable = " . $array_name;
}
}
listArrayRecursive($someArray);
将打印:
1 :
2 :
3 : end
6 : end
3 :
6 : end
4 :
3 :
7 : end
现在,我怎样才能在每次到达末尾时打印数组的路径?例如:
1 :
2 :
3 : end : path -> 1,2,3
6 : end : path -> 1,2,6
3 :
6 : end : path -> 1,3,6
4 :
3 :
7 : end : path -> 4,3,7
编辑了添加第三个参数以记录路径的代码:
$someArray[1][2][3] = 'end';
$someArray[1][2][6] = 'end';
$someArray[1][3][6] = 'end';
$someArray[4][3][7] = 'end';
$someArray[3][2] = 'end';
function listArrayRecursive(&$array_name, $ident = 0, $path = null){
foreach ($array_name as $k => &$v){
if (is_array($v)){
for ($i=0; $i < $ident * 10; $i++){ echo " "; }
echo $k . " : " . "<br>";
$path .= $k . ', ';
listArrayRecursive($v, $ident + 1, $path);
}else{
for ($i=0; $i < $ident * 10; $i++){ echo " "; }
echo $k . " : " . $v . ' - path -> ' . $path . "<br>";
}
}
}
listArrayRecursive($someArray);
将打印:
1 :
2 :
3 : end - path -> 1, 2,
6 : end - path -> 1, 2,
3 :
6 : end - path -> 1, 2, 3,
4 :
3 :
7 : end - path -> 1, 4, 3,
3 :
2 : end - path -> 1, 4, 3,
您可以使用RecursiveIteratorIterator
(文档(来消除通过数组递归的艰苦工作。
function listArrayRecursive($someArray) {
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($someArray), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $k => $v) {
$indent = str_repeat(' ', 10 * $iterator->getDepth());
// Not at end: show key only
if ($iterator->hasChildren()) {
echo "$indent$k :<br>";
// At end: show key, value and path
} else {
for ($p = array(), $i = 0, $z = $iterator->getDepth(); $i <= $z; $i++) {
$p[] = $iterator->getSubIterator($i)->key();
}
$path = implode(',', $p);
echo "$indent$k : $v : path -> $path<br>";
}
}
}
这个例子是为了给你想法,而不是解决实际任务。
function recursiveSearch($array,$search){
foreach($array as $key=>$val){
if($val==$search)return $key;
$x=recursiveSearch($array[$key],$search);
if($x)return $key.' -> '.$x;
}
}
echo recursiveSearch($array,'search');
如果未找到匹配项,则返回 null。
$a= array(1,2,3,4,5,6);
$val = end($a);
print_array($a,$val);
function print_array(&$arr, $val)
{
if ($val === false)
return;
$curr = prev($arr);
print_array($arr,$curr);
echo $val;
}
我刚刚编写了一个使递归循环更容易的函数:与array_walk_recursive类似,但具有一些额外的功能
public static function walk($array, $callback, $custom = null, $recursive = false, $info = [])
{
$r = $recursive;
if (gettype($r) === 'integer') {
$r--;
}
$info['depth'] = empty($info)?1:$info['depth'] + 1;
$info['count'] = count($array);
$info['i'] = 1;
foreach($array as $k => $v) {
if (is_array($v) && $r > 0) {
$array[$k] = static::walk($v, $callback, $custom, $r, $info);
} else {
$array[$k] = $callback($v, $k, $custom, $info);
}
$info['i'] ++;
}
return $array;
}
public static function walkable($v, $k, $custom, $info)
{
if (is_string($v)) {
return $v." [ custom: {$custom['key']} ] [ level: ".$info['depth'].' | No '.$info['i'].' of '.$info['count']." ]";
}
return $v;
}
这样称呼:
$result = NamespaceClassName::walk($array, ['NamespaceClassName', 'walkable'], ['key'=>'value'], true);
将递归设置为 false 将仅评估第一级。
将递归设置为 true 将导致它遍历整个数组。
将递归设置为整数将导致它仅遍历到该深度。
可步行函数可以作为匿名函数引用或传递给回调。
(期望:值、键、自定义、信息(返回值将替换当前值。
可以传递自定义数据,并为您提供一些其他信息。
如果需要其他信息,可以扩展步行功能。
我也有类似的问题。这是一个深度优先搜索式解决方案(不包括路径深度,它一直到达数组的最后(。如果您不想包含该值,请注释"if"语句:
$output = array();
retrievePath($someArray, $output);
function retrievePath($someArray, array &$pathKeeper)
{
if(!is_array($someArray)){ // $someArray == "end"
$element = array_pop($pathKeeper) ?? '';// if the array is empty pop returns null, we don't want that
array_push($pathKeeper, $element . '->'. $someArray);
} else{
end($someArray);//we want to get the last element from the array so we move the internal pointer to it's end
$endElKey = key($someArray);//take the key where the pointer is
reset($someArray);
foreach($someArray as $key=>$value){
$element = array_pop($pathKeeper);
array_push($pathKeeper, $element === null ? $key : $element . '->' . $key);// we don't want '->' at the beginning
retrievePath($value, $pathKeeper);
if($key != $endElKey) //we check whether this is not the last loop
array_push($pathKeeper, $element);
}
}
}
<?php
function printListRecursive($a, $var='', $i = 0) {
if (!is_array($a)) {
$var .= $a;
return $var;
}
$string = "";
foreach ($a as $k => $value) {
$string .= str_repeat(" ", $i) .' - '. $k . ':';
if (!is_array($value)) {
$string .= $value . '<br />';
} else {
$string .= '<br />';
$string .= printListRecursive($value, $var, $i + 1);
}
}
return $string;
}
$test_array = [
'America' => [
'Argentina' => 'Buenos Aires',
'Peru' => 'Lima'
],
'Europe' => [
'Ireland' => 'Dublin',
'France' => 'Paris',
'Italy' => 'Rome'
]
];
$result = printListRecursive($test_array);
echo $result;
?>
在此处检查代码
我根据@salathe的函数想出了以下函数。它返回一个数组,其中每个元素都是一个数组,其中包含索引 0 处的叶子和索引 1 处的路径键数组:
function loosenMultiDimensionalArrayPathForEachVal($array) {
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::SELF_FIRST);
$iterator->rewind();
$res = [];
foreach ($iterator as $v) {
$depth = $iterator->getDepth();
for ($path = array(), $i = 0, $z = $depth; $i <= $z; $i++) {
$path[] = $iterator->getSubIterator($i)->key();
}
$leaf = $array;
foreach ($path as $pathKey) {
$leaf = $leaf[$pathKey];
}
if (!is_array($leaf)) {
$res[] = [
$v,
$path
];
}
}
return $res;
}
我实现这个的主要原因是,如果当前迭代的叶子是一个对象,$iterator->hasChildren()
返回true
。因此,我无法以这种方式获得它的道路。
我找到了这个解决方案,如果结构的元素是数组,它也考虑了:
$file_contents=file_get_contents("data.json");
$json_dump=json_decode($file_contents);
printPath($json_dump, '', "" ,"");
function printPath($the_array, $path, $prevType) {
// Parse all elements of a structure
// and print full PHP path to each one.
foreach($the_array as $key => $value) {
if(is_array($value)) {
// Array element cannot be directly printed: process its items as objects:
printPath($value, $path . $key , "array");
} else {
if (!is_object($value)) { // If the element is not an object, it can be printed (it's a leaf)
if(is_string($value)) {
$finalValue = '"' . $value . '"';
} else {
$finalValue = $value;
}
if($prevType == "array") {
// If array element, add index in square brackets
echo($path . "[" . $key . "] = " . $finalValue . "<br>");
} else {
echo($path . $key . " = " . $finalValue . "<br>");
}
} else { // else store partial path and iterate:
if($prevType == "array") {
// Path of array element must contain element index:
printPath($value, $path . "[" . $key . "]->" , "dummy");
} else {
printPath($value, $path . $key . "->", "dummy");
}
}
}
}
}
示例输出:
status->connections->DSS-25->band = "X"
status->connections->DSS-25->endAt = "2019-11-20T20:40:00.000Z"
status->connections->DSS-25->startAt = "2019-11-20T12:40:00.000Z"
geometry[0]->obs[0]->name = "UDSC64"
geometry[0]->obs[0]->hayabusa2->azm = 90.34
geometry[0]->obs[0]->hayabusa2->alt = -20.51
如果有人感兴趣,这里是Javascript的端口:
function iterate(obj, stack, prevType) {
for (var property in obj) {
if ( Array.isArray(obj[property]) ) {
//console.log(property , "(L=" + obj[property].length + ") is an array with parent ", prevType, stack);
iterate(obj[property], stack + property , "array");
} else {
if ((typeof obj[property] != "string") && (typeof obj[property] != "number")) {
if(prevType == "array") {
//console.log(stack + "[" + property + "] is an object, item of " , prevType, stack);
iterate(obj[property], stack + "[" +property + "]." , "object");
} else {
//console.log(stack + property , "is " , typeof obj[property] , " with parent ", prevType, stack );
iterate(obj[property], stack + property + ".", "object");
}
} else {
if(prevType == "array") {
console.log(stack + "[" + property + "] = "+ obj[property]);
} else {
console.log(stack + property , " = " , obj[property] );
}
}
}
}
}
iterate(object, '', "File")
您可以添加第三个参数,该参数将实际路径保存为 String。最后你可以输出它。