PHP搜索JSON而不循环

I have a large JSON array which is the result of querying the API of an Icinga2 monitoring system.

I have used json_decode like this in my code to decode it:

$response = json_decode($array, true);

and I can see the output looks like this:

        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
            )

There are 400 Records in total and it's quite a complex structure but the only bits I am really interested in are the name and state fields. Basically my script has a list of 150 hostnames from another source and what I want to do is for each hostname, search for it in the array and return the value of the state field for that host. So far I've been struggling to do this without looping through the entire array for each of the 150 hostnames. There must be a more efficient way to do a lookup in the array based on a hostname and return a single value but I can't figure it out.

Given, the name field has no logical sorting inside the json result, there is no way to look at least once at each element. If they are sorted alphabetical, you could use a simple binary search, which would give you the result in O(log(n)).

The other thing is, if you have to search for multiple names, you could put them inside an name assiciated array. This way, you only have an initial overhead of O(n) building the list and each following search would return you the state on O(1).

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

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

I'm hoping that I've got the source data array in the correct layout as the format was a bit confusing from the original question. But the main idea is to use array_column to extract the "attrs" and key the result by the "name" element of this array.

$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);

With the sample data, this gives...

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
        )

)

So to find any server by name, you'd use

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

If you only wanted the state field (as you asked for) and wanted to simplify the array, you can then use...

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

The array_walk() goes through the array and just copies the state field to be the entry, so the result of this is...

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

So now you just do...

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