我需要在数组中找到一个特定的键,并返回它的值和路径以找到该键。例如:
$array = array(
'fs1' => array(
'id1' => 0,
'foo' => 1,
'fs2' => array(
'id2' => 1,
'foo2' => 2,
'fs3' => array(
'id3' => null,
),
'fs4' => array(
'id4' => 4,
'bar' => 1,
),
),
),
);
search($array, 'fs3'); // Returns ('fs1.fs2.fs3', array('id3' => null))
search($array, 'fs2'); // Returns ('fs1.fs2', array('id2' => 1, ... ))
我已经能够通过数组递归找到正确的密钥并使用RecursiveArrayIterator
返回数据(如下所示),但我不知道跟踪的最佳方法我现在走的路是什么。
$i = new RecursiveIteratorIterator
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST);
foreach ($i as $key => value) {
if ($key === $search) {
return $value;
}
}
答案 0 :(得分:4)
仅为完成和未来的访客。结合上面的示例代码和我评论的答案来获取密钥。这是一个工作函数,它将通过一个小的更改返回请求的结果。在我的返回数组中,我返回了密钥path
和value
,而不是请求的0
和$search
。我发现这更详细,更容易处理。
<?php
$array = array(
'fs1' => array(
'id1' => 0,
'foo' => 1,
'fs2' => array(
'id2' => 1,
'foo2' => 2,
'fs3' => array(
'id3' => null,
),
'fs4' => array(
'id4' => 4,
'bar' => 1,
),
),
),
);
function search($array, $searchKey=''){
//create a recursive iterator to loop over the array recursively
$iter = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST);
//loop over the iterator
foreach ($iter as $key => $value) {
//if the key matches our search
if ($key === $searchKey) {
//add the current key
$keys = array($key);
//loop up the recursive chain
for($i=$iter->getDepth()-1;$i>=0;$i--){
//add each parent key
array_unshift($keys, $iter->getSubIterator($i)->key());
}
//return our output array
return array('path'=>implode('.', $keys), 'value'=>$value);
}
}
//return false if not found
return false;
}
$searchResult1 = search($array, 'fs2');
$searchResult2 = search($array, 'fs3');
echo "<pre>";
print_r($searchResult1);
print_r($searchResult2);
输出:
Array
(
[path] => fs1.fs2
[value] => Array
(
[id2] => 1
[foo2] => 2
[fs3] => Array
(
[id3] =>
)
[fs4] => Array
(
[id4] => 4
[bar] => 1
)
)
)
Array
(
[path] => fs1.fs2.fs3
[value] => Array
(
[id3] =>
)
)
答案 1 :(得分:1)
看起来你假设钥匙永远是唯一的。我不这么认为。因此,您的函数必须返回多个值。我要做的只是写一个递归函数:
function search($array, $key, $path='')
{
foreach($array as $k=>$v)
{
if($k == $key) yield array($path==''?$k:$path.'.'.$k, array($k=>$v));
if(is_array($v))
{ // I don't know a better way to do the following...
$gen = search($v, $key, $path==''?$k:$path.'.'.$k);
foreach($gen as $v) yield($v);
}
}
}
这是一个递归生成器。它返回一个包含所有命中的生成器。它非常像数组:
$gen = search($array, 'fs3');
foreach($gen as $ret)
print_r($ret); // Prints out each answer from the generator
答案 2 :(得分:1)
已经有RecursiveIteratorIterator使用的答案。我的解决方案可能并不总是最优的,我没有测试估计时间。可以通过重新定义callHasChildren
的{{1}}方法对其进行优化,以便在找到键时不会有子项。但这不属于领域。
以下是您不必使用显式内循环的方法:
RecursiveIteratorIterator
注意function findKeyPathAndValue(array $array, $keyToSearch)
{
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::CHILD_FIRST
);
$path = [];
$value = null;
$depthOfTheFoundKey = null;
foreach ($iterator as $key => $current) {
if (
$key === $keyToSearch
|| $iterator->getDepth() < $depthOfTheFoundKey
) {
if (is_null($depthOfTheFoundKey)) {
$value = $current;
}
array_unshift($path, $key);
$depthOfTheFoundKey = $iterator->getDepth();
}
}
if (is_null($depthOfTheFoundKey)) {
return false;
}
return [
'path' => implode('.', $path),
'value' => $value
];
}
。该标志反转迭代的顺序。所以我们可以只使用一个循环来准备路径 - 这实际上是递归迭代器的主要目的。它们隐藏了你的所有内环。
这是working demo。
答案 3 :(得分:0)
如果您需要返回所有项与特定键匹配的数组,则可以使用php generators
function recursiveFind(array $haystack, string $needle, $glue = '.'): ?\Generator
{
$recursive = new \RecursiveIteratorIterator(
new \RecursiveArrayIterator($haystack),
\RecursiveIteratorIterator::SELF_FIRST
);
foreach ($recursive as $key => $value) {
//if the key matches our search
if ($key === $needle) {
//add the current key
$keys = [$key];
//loop up the recursive chain
for ($i = $recursive->getDepth() - 1; $i >= 0; $i--) {
array_unshift($keys, $recursive->getSubIterator($i)->key());
}
yield [
'path' => implode($glue, $keys),
'value' => $value
];
}
}
}
用法:
foreach (recursiveFind($arrayToSearch, 'keyName') as $result) {
var_dump($result);
}