PHP搜索JSON而不循环

时间:2018-06-11 16:23:28

标签: php arrays json

我有一个大的JSON数组,它是查询Icinga2监控系统的API的结果。

我在我的代码中使用了这样的json_decode来解码它:

$response = json_decode($array, true);

我可以看到输出如下:

        Array
            (
                [results] => Array
                    (
                        [0] => Array
                            (
                                [attrs] => Array
                                    (
                                        [__name] => HOSTNAME0
                                        [acknowledgement] => 0
                                        [acknowledgement_expiry] => 0
                                        ...
                                        ...
                                        [state] => 0
                                        [state_type] => 1
                                 [meta] => Array
                                     (
                                     )

                                 [name] => HOSTNAME0
                                 [type] => Host
            )


                        [1] => Array
                            (
                                [attrs] => Array
                                    (
                                        [__name] => HOSTNAME1
                                        [acknowledgement] => 0
                                        [acknowledgement_expiry] => 0
                                        ...
                                        ...
                                        [state] => 0
                                        [state_type] => 1   
                                 [meta] => Array
                                     (
                                     )

                                 [name] => HOSTNAME1
                                 [type] => Host
            )

总共有400条记录,它的结构非常复杂,但我唯一感兴趣的是名称和州字段。 基本上我的脚本有一个包含来自另一个源的150个主机名的列表,我想要做的是为每个主机名,在数组中搜索它并返回该主机的state字段的值。 到目前为止,我一直在努力做到这一点,而不是为150个主机名中的每一个循环遍历整个数组。必须有一种更有效的方法在数组中基于主机名进行查找并返回单个值,但我无法弄清楚。

2 个答案:

答案 0 :(得分:0)

鉴于,name字段在json结果中没有逻辑排序,没有办法在每个元素上至少查看一次。如果它们按字母顺序排序,您可以使用简单的二进制搜索,这将在O(log(n))中为您提供结果。

另一件事是,如果你必须搜索多个名字,你可以把它们放在一个名字附属数组中。这样,您只需要O(n)构建列表的初始开销,并且每个后续搜索都会返回O(1)上的状态。

// building the array
$states = [];
foreach ($items as $item) {
    $states[$item['name']] = $item['state'];
}

looking for HOSTNAME1
$state = $states['HOSTNAME1'];

答案 1 :(得分:0)

我希望我的源数据数组在正确的布局中,因为格式与原始问题有点混淆。但主要的想法是使用array_column提取“attrs”并通过此数组的“name”元素键入结果。

$response = Array(
    "results" => Array(
        0 => Array(
            "attrs" => Array(
                "__name" => "HOSTNAME0",
                "acknowledgement" => 0,
                "acknowledgement_expiry" => 0,
                "state" => 0,
                "state_type" => 1
            ),
            "name" => "HOSTNAME0",
            "type" => "Host"
        ),
        1 => Array(
            "attrs" => Array(
                "__name" => "HOSTNAME1",
                "acknowledgement" => 0,
                "acknowledgement_expiry" => 0,
                "state" => 2,
                "state_type" => 1
            ),
            "name" => "HOSTNAME1",
            "type" => "Host1"
        )
    )
);

$extract = array_column($response["results"], "attrs", "name");
print_r($extract);

使用样本数据,这给出了......

Array
(
    [HOSTNAME0] => Array
        (
            [__name] => HOSTNAME0
            [acknowledgement] => 0
            [acknowledgement_expiry] => 0
            [state] => 0
            [state_type] => 1
        )

    [HOSTNAME1] => Array
        (
            [__name] => HOSTNAME1
            [acknowledgement] => 0
            [acknowledgement_expiry] => 0
            [state] => 2
            [state_type] => 1
        )

)

因此,要按名称查找任何服务器,请使用

echo "HOSTNAME1=".$extract["HOSTNAME1"]["state"].PHP_EOL;

如果您只想要状态字段(如您所要求的那样)并希望简化数组,那么您可以使用...

array_walk($extract, function(&$data) {$data=$data["state"];});
print_r($extract);

array_walk()遍历数组并只将状态字段复制为条目,因此结果是......

Array
(
    [HOSTNAME0] => 0
    [HOSTNAME1] => 2
)

所以现在你做...

echo "HOSTNAME1=".$extract["HOSTNAME1"].PHP_EOL;