2

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.

6
  • Is it a json text string? Commented Sep 21, 2017 at 6:28
  • Efficient as in microoptimize, or efficient as in memory usage, or efficient as in code written? Commented Sep 21, 2017 at 6:29
  • @Andreas it originally exists as a JSON text string, correct Commented Sep 21, 2017 at 6:33
  • @mario, efficient as in not loop through 100 nested arrays looking at each one, and instead using a function like array_filter(), which doesn't quite fit the bill Commented Sep 21, 2017 at 6:33
  • What you have tried so far? Can you please post your inputs Commented Sep 21, 2017 at 6:33

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Across 10000 iterations, this function is more efficient, and returning the keypairs could come in handy. I'm changing the accepted answer to this one, thanks @LSemi
1

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

2 Comments

Thanks for the answer @Andreas, but I prefer Jigar's answer which uses the PHP array functions
Sure. No problem.
1

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

2 Comments

Brilliant, exactly the sort of thing I was looking for. I'd just stumbled upon the array_search/array_column trick, but was having trouble getting it working properly.
Thanks, glad to help you :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.