PHP search JSON without looping - php

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;

Related

Array index stuck at [0]

I am trying to create an array out of looped data. The variables contain looped data. All works fine, but when array is outputted, the index gets stuck at 0 and doesn't move up from 0 to 1 etc. I wonder what the problem is and how I can get this fixed.
Thanks.
$productinfo = array(
array(
"Productname" => "$productname",
"StarRating" => "$starrating",
"AddedValue" => "$addedvalue",
"ProductImage" => "$image",
"TotalPrice" => "$totalprice",
"ProductLink" => "$link" )
);
$productinfojson= json_encode($productinfo);
$output = json_decode($productinfojson, TRUE);
echo "<pre>";
print_r( $output );
echo "</pre>";
The above outputs:
Array
(
[0] => Array
(
[Procuctname] => Pencil Stack
[StarRating] => 3
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 5.50
[ProductLink] => http://---.net/product
)
)
Array
(
[0] => Array
(
[Procuctname] => Block Bundle
[StarRating] => 4
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 15
[ProductLink] => http://---.net/product
)
)
UPDATE if only one array is used.
code:
$productinfo = array(
"Productname" => "$productname",
"StarRating" => "$starrating",
"AddedValue" => "$addedvalue",
"ProductImage" => "$image",
"TotalPrice" => "$totalprice",
"ProductLink" => "$link" );
OUTPUT
Array
(
[Procuctname] => Pencil Stack
[StarRating] => 3
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 5.50
[ProductLink] => http://---.net/product
)
Array
(
[Procuctname] => Block Bundle
[StarRating] => 4
[AddedValue] => Free Delivery
[ProductImage] =>
[TotalPrice] => 15
[ProductLink] => http://---.net/product
)
The issue stems straight from your array creation. There doesn't seem to be a loop anywhere in your code either....
Anyways, lets sort out your array creation. I assume you're getting the data from a database/data source and assigning it to variables, inputting it into an array? Well the way you currently have it, it's overwriting the first index element in the array.
Disclaimer: The below is pseudo code, until you update with your actual loop code..
$productinfo = array();
while($row = FETCH_DATA_FROM_SQL()) {
// assign it to variables here...?
$productinfo[] = array(
"Productname" => "$productname",
"StarRating" => "$starrating",
"AddedValue" => "$addedvalue",
"ProductImage" => "$image",
"TotalPrice" => "$totalprice",
"ProductLink" => "$link"
);
}
That will add each element to the new $productinfo array and you should be able to loop through the elements correctly.
One more thing to note, you're decoding your json like this:
$output = json_decode($productinfojson, TRUE);
That second parameter (TRUE), turns it into an associative array, not an object. So when you loop it as an object like below:
foreach($response->products->product as $product) {...
It isn't going to work. If you want it as an object, remove the second parameter (TRUE), otherwise loop it as an array:
foreach($response['products']['product'] as $product) {...

How to search a multidimensional array to return multiple keys

I've got a multidimensional array written in php that holds an array of arrays. I've read a lot about how to search this, but it seems most solutions either:
A. require you have unique values for the keys, such as a product id
or
B. are satisfied with returning multiple results in an array
I am looking to search the array given the round number (which is the array number of the highest/first level array), and a player name (which will be the value of either the key player 1 or player 2).
The array looks something like this:
Array (
[0] => Array ( )
[8] => Array (
[1] => Array (
[Match] => 1
[Player1seed] => (Q)
[Player1name] => Mahut
[Player2seed] => (2)
[Player2name] => Goffin
[Matchscore] => 7-6(1), 6-1
[Round] => Finals
)
)
[7] => Array (
[1] => Array (
[Match] => 1
[Player1seed] => (2)
[Player1name] => Goffin
[Player2seed] =>
[Player2name] => Muller
[Matchscore] => 7-6(4), 6-4
[Round] => Semi-Finals
)
[2] => Array
(
[Match] => 2
[Player1seed] => (Q)
[Player1name] => Mahut
[Player2seed] => (WC)
[Player2name] => Haase
[Matchscore] => 5-7, 6-3, 6-4
[Round] => Semi-Finals
)
)
etc.
Essentially, I need to be able to search specifically one subset such as array[7] and be returned the results that contains either player1 or player2 as a name, say Goffin.
But I don't want it to return results from other tournament rounds such as array[8] or array[6] where either player is Goffin.
I can't seem to find this solution anywhere. Am I setting up my array incorrectly? Or expecting database functions from a lesser data set?
Any help would be appreciated.
It's not exactly the way I wanted to solve the problem, but I was able to get the results I wanted by running a loop after identifying the specific round number:
$r = $roundnumber;
foreach( $matchesarray[$r] AS $key=>$data ){
$winnerseed=$data['Player1seed'];
$winnername=$data['Player1name'];
$loserseed=$data['Player2seed'];
$losername=$data['Player2name'];
$matchurl=$data['Matchurl'];
$score=$data['Matchscore'];
if ($p1name == $winnername || $p2name == $losername){
$winner=$p1;
}
else if ($p2name == $winnername || $p1name == $losername){
$winner=$p2;
}
}

Get array value by dynamic key in php

maybe I am totally blind but i have an array:
Array ( [p541] => 1 [p747] => 1 [p792] => 1 [p968] => 1 [p2157] => 1 [clickeditem] => 0WCr9ParDzLD9wpctknt0XErhOZcX33wXfgGDNpSoIo= [actualtime] => 11832 [timekey] => 1406227645 [actualuser_id] => V58yD4MQ2ZwTumjivhhQL/BSFXsu0Dvoj0bxp7Tu8PM= [timeout] => 0 [report_misuse] => 0 [A1] => 5RC52CZHPV8f0Zw+FYGZel5Ay2YcLVjrY8MBplz1zJA= [B1] => 0WCr9ParDzLD9wpctknt0XErhOZcX33wXfgGDNpSoIo= [B2] => KnCK/vIcQ5PAwJxjUMh0w+NTM+TqdVG9+Tiyi0U9QWM= [B3] => DhT8qBQFQC+dE/Rku7wdMJ4bw6dtFp8hzfmxPMCrItQ= [B4] => ZE30ASB6IUQglpXNiOUxdmiYpJnEbuKKXIaUZO9w4mU= [B5] => IXyGTO6V/8uZOK5y81DnI58xumZ0CIkFsTQwUWJ2CyE= [pageloadtime] => 0.179646 [option] => com_findme [view] => pair )
but I want to get the value for "p541"
$name= "p541";
$value = $array [$name];
does not work ???
If your array variable is named $array, try this:
$value = $array['p541'];
What you're doing is creating a new array named $value containing the variable $name, which is not what we want.
Your array items need to be comma separated and not within [ ] if you're declaring associative arrays like that. You also need to save your array to a variable so you can access it.
$value = array('p541' => 1, 'p747' => 2, 'p792' => 3);
then this...
$value['p541']
will equal 1

Rewrite array keys by matching it to first child key, possible in php?

I'm wondering if there is an easy way to match array key to logo_id?
If I cannot find a way to do this, I will need to use array search which can become quite slow with an array of 200 items. Right?
p.s. this is result returned by mysqli fetch result call. Maybe this can be modified to provide array which I need?
Array
(
[0] => Array
(
[logo_id] => 1
[logo_name] => beeline
[logo_level] => 1
[logo_image_path] => logos/1.png
[logo_value] => 2
[logo_hints] =>
)
[1] => Array
(
[logo_id] => 2
[logo_name] => geocell
[logo_level] => 1
[logo_image_path] => logos/2.png
[logo_value] => 4
[logo_hints] =>
)
[2] => Array
(
[logo_id] => 3
[logo_name] => google
[logo_level] => 1
[logo_image_path] => logos/3.png
[logo_value] => 5
[logo_hints] =>
)
[3] => Array
(
[logo_id] => 5
[logo_name] => coca cola
[logo_level] => 1
[logo_image_path] => logos/5.png
[logo_value] => 2
[logo_hints] =>
)
)
Did I explain it good? phh, sorry for bad wording.
this is result returned by mysqli fetch result call. Maybe this can be modified to provide array which I need?
Yes. I assume you mean mysqli_result::fetch_all. Use mysqli_result::fetch_row in a loop instead and construct your array manually with whatever keys you like to.

Cakephp using Set class to fetch data with key starting at zero

I'm using Set class of Cakephp to format the find returned array but cannot seem to find a way to get the counter starting at zero and auto-increment for array keys so it is like
[0] => 3
[1] => 6
[2] => 12
I'm currently using below query to get the data from my HasAndBelongsToMany table.
$interest_ids = Set::combine($this->User->Interestsub->find('threaded', array
(
'conditions' => array
(
'Interestsub.name' => $interests
),
//'fields' => array('Interestsub.id'),
'recursive' => -1
)
),
'{n}.Interestsub.id',
'{n}.Interestsub.id'
);
The reason why I need this is that I'm currently trying to get the returned array as part of bigger parent array preparing to be saved for SaveAll function. To be formatted properly, I need below nested array coming out:
[0] => Array
(
[interestssub_id] => 12
[user_id] => 2
)
[1] => Array
(
[interestssub_id] => 22
[user_id] => 2
)
[2] => Array
(
[interestssub_id] => 32
[user_id] => 2
)
Is there a way we can use Combine class to format the returned array like above?
There's no real reason to use the Set class in this case. Just use good old fashioned php:
$threaded = $this->User->Interestsub->find('threaded', array(
'conditions' => array(
'Interestsub.name' => $interests
),
'recursive' => -1
));
$interest_ids = array();
foreach ($threaded as $thread) {
$interest_ids[] = array(
'interestssub_id' => $thread['Interestsub.id'],
'interestssub_id' => $thread['Interestsub.user_id']
);
}

Categories