【问题标题】:PHP Recursive JSON Children SearchPHP 递归 JSON 子项搜索
【发布时间】:2017-05-10 05:08:39
【问题描述】:

我需要解析如下所示的 JSON:

{
    "mdfId":"282088127",
    "mdfConcept":"ME 3400EG-12CS-M Switch",
    "children":[
        {
            "mdfId":"007",
            "mdfConcept":"Another item",
            "children": [
                // many more here
            ]
        },
        {
             "mdfId":"008",
             "mdfConcept":"Another one",
             "children": [
                 {
                     "mdfId":"010",
                     "mdfConcept":"What I'm looking for!",
                     "children": [] // no children
                 }
             ]
        },
        // many more here
    ]
},

这是一个递归结构,其中每个元素都有mdfIdmdfConceptchildren 键。

假设我需要在这个结构中找到带有ID=010 的节点。我不知道它位于哪个级别(例如,它可以位于顶层,也可以位于下面的几个 children 节点)。

我目前的做法是:

$mdfId = '010'; // what I'm loking for

foreach ($jsonResponse as $category) {
    while (true) {
        if ($category['mdfId'] == $mdfId) {
            // we found it!
            $categoryDevices[$mdfId] = $category['children'];
            break 2;
        }

        if (!empty($category['children'])) {
            next_cat:

            if (is_null($category['children'])) {
                break;
            }

            $category = array_shift($category['children']);
            continue;
        }

        if (empty($category['children'])) {
            goto next_cat;
        }
    }
}

但目前的方法会遗漏一些情况。如何优化这个递归循环,以便它检查同一级别的所有节点,并且每个节点都可以通过任意数量的 children 键访问?

【问题讨论】:

    标签: php loops recursion logic


    【解决方案1】:

    您的 JSON 对象的一个​​令人尴尬的特性是,虽然每个 children 成员都是“子”结构的数组,顶层是对象本身,所以这是一个障碍真正的递归方法。

    我们可以通过将源 JSON 对象转换为与嵌套级别相同的结构来解决问题,即:

    • $jsonResponse 作为原始对象
    • 改用['children' => $jsonResponse]

    这样,它应该可以使用这样的东西:

    $mdfId = '010'; // what I'm loking for
    
    if ($result = look4id(['children' => $jsonResponse], $mdfId) {
        $categoryDevices[$mdfId] = $result;
    }
    
    function look4id($source, $id) {
        foreach ($source as $child) {
            if ($child['mdfId'] == $id) {
                return $source['children'];
            } else {
                if ($source['children']) {
                    return look4id($source['children'], $id);
                }
            }
        }
    }
    

    【讨论】:

    • 总体上很好的答案和方法。允许我将发现率从 30% 提高到 60%。但是,一旦循环进入多个children 深度,它就会忘记更高级别上未触及的元素。因此,如果007008 以相反的顺序放置,脚本将检查008 及其子010,但完全错过了007
    • @DenisBobrovnikov 哼...有趣的问题!您能否发布一个 JSON 对象的示例,如果不是太重,找不到哪个键? (您可以编辑您的 OP 并将对象放入 SO sn-p)
    【解决方案2】:

    所以基本上我编写了一个不返回任何内容的函数,而是从参数中填充了一个变量。

    function findRecursiveArrayNodeById($id, $array, &$node) {
        foreach ($array as $child) {
            if (isset($child['mdfId']) && $child['mdfId'] == $id) {
                $node = $child;
                return;
            }
    
            if (!empty($child['children'])) {
                findRecursiveArrayNodeById($id, $child['children'], $node);
            }
        }
    }
    

    用法如下:

    $result = false;
    
    findRecursiveArrayNodeById($mdfId, $category_json, $result);
    
    if (!$result) {
        println("did not find {$mdfId}");
        continue;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-10
      • 2010-12-24
      • 2013-06-17
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 2014-10-15
      相关资源
      最近更新 更多