Reputation: 4820
Suppose a PHP array, when cast to JSON, has the following format:
[{
"key": "width",
"value": "1200",
"label": "Width (mm)",
"choice": ""
},
{
"key": "height",
"value": "900",
"label": "Height (mm)",
"choice": ""
},
{
"key": "material",
"value": "paper",
"label": "Material",
"choice": "Paper"
}]
(This is a shortened version of the original, which can have many more elements)
Let's suppose I want to efficiently find what material is used. In other words, I want to search for a nested array that has for key
the value material
, and I want to return the value
which would be paper
.
I know this can be done by using a foreach/while loop, but PHP is rich with compiled array functions that I'm not very familiar with. What's the best function to use here?
UPDATE: What I've tried so far
Here's two things I've tried so far:
Attempt #1:
$json = '[{"key":"width","value":"1200","label":"Width (mm)","choice":""},{"key":"height","value":"900","label":"Height (mm)","choice":""},{"key":"material","value":"paper","label":"Material","choice":"Paper"}]';
$array = json_encode($json, true);
$material = '';
foreach($array as $nestedArray) {
if($nestedArray['key'] = 'material') {
$material = $nestedArray['value'];
}
}
Attempt #2:
$json = '[{"key":"width","value":"1200","label":"Width (mm)","choice":""},{"key":"height","value":"900","label":"Height (mm)","choice":""},{"key":"material","value":"paper","label":"Material","choice":"Paper"}]';
$array = json_decode($json, true);
$filteredArray = array_filter($array, function($array) {
return ($array['key'] == 'material');
});
$arr = array_pop($filteredArray)['value'];
Both produce the right value, but #1 is messy, and #2 may not be the best use of PHPs array functions.
Upvotes: 2
Views: 2207
Reputation: 57388
It depends on what you want to do in addition to "finding the value". And what you have.
array_filter
is simple, but it will loop through the whole array.
array_search
on a reduced set looks faster, but it needs to make a copy of the source array, so it's actually slower than array_filter
(not by much).
The foreach
solution you tried first will not create extra arrays and it allows you to break on a find:
foreach($array as $nestedArray) {
if ($nestedArray['key'] == 'material') {
$material = $nestedArray['value'];
break; // <--- found!
}
}
So on short arrays I'd go with the accepted solution using array_column
, or if you're sure that the material is there, there is this array_column
tweak:
// Transform the records into keypairs
$keypairs = array_column($records, 'value', 'key');
Now keypairs is [ width => 900, material => paper, ... ], so:
$material = $keypairs['material'];
I'd add a array_key_exists
just to be sure. This saves the array_search
(not that great an advantage, but you might have a use for the keypair object).
If you need exactly that one value and nothing else, performance is at a premium, and the array is large, I'd not throw out the idea of looking for '"material":"' inside the JSON as a string with strpos
, even if it's a code smell.
Upvotes: 2
Reputation: 6223
You can use combination of array_search and array_column so no need to use loop
Working Demo: https://eval.in/865566
$data = '[{
"key": "width",
"value": "1200",
"label": "Width (mm)",
"choice": ""
},
{
"key": "height",
"value": "900",
"label": "Height (mm)",
"choice": ""
},
{
"key": "material",
"value": "paper",
"label": "Material",
"choice": "Paper"
}]';
$data = json_decode($data,True);
$key = array_search('material', array_column($data, 'key')); // get key of array
echo $data[$key]['value'];
Output
paper
Upvotes: 1
Reputation: 23958
If it's a json text as you stated in comments my advice is a regex match.
This will find "key material" and "value" and match the value of value.
It works on the small sample, but you have to try it on a larger string.
https://regex101.com/r/CSTLUL/1
$re = '/key\": \"material\",.*?\"value\": \"(.*?)\",/s';
$str = '{
"key": "width",
"value": "1200",
"label": "Width (mm)",
"choice": ""
},
{
"key": "height",
"value": "900",
"label": "Height (mm)",
"choice": ""
},
{
"key": "material",
"value": "paper",
"label": "Material",
"choice": "Paper"
}]';
preg_match_all($re, $str, $matches);
// Print the entire match result
var_dump($matches);
Upvotes: 1