Эффективно найти вложенный элемент массива PHP на основе значения атрибута

Предположим, что массив PHP, когда он передан в 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" }] 

(Это сокращенная версия оригинала, которая может содержать гораздо больше элементов)

Предположим, я хочу эффективно найти, какой материал используется. Другими словами, я хочу найти вложенный массив, который имеет для key значение material , и я хочу вернуть value которое будет paper .

Я знаю, что это можно сделать, используя цикл foreach / while, но PHP богат скомпилированными функциями массива, с которыми я не очень хорошо знаком. Какая функция лучше всего использовать здесь?


ОБНОВЛЕНИЕ: что я пробовал до сих пор

Вот две вещи, которые я пробовал до сих пор:

Попытка № 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']; } } 

Попытка № 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']; 

Оба генерируют правильное значение, но # 1 беспорядочно, а # 2 – не лучшее использование функций массива PHP.

Это зависит от того, что вы хотите сделать в дополнение к «нахождению значения». И что у вас есть.

array_filter прост, но он будет проходить через весь массив.

array_search на уменьшенном наборе выглядит быстрее, но он должен сделать копию исходного массива, поэтому он на самом деле медленнее, чем array_filter (не сильно).

Решение foreach вы пробовали вначале, не будет создавать дополнительные массивы, и это позволит вам разбить находку:

 foreach($array as $nestedArray) { if ($nestedArray['key'] == 'material') { $material = $nestedArray['value']; break; // <--- found! } } 

Поэтому на коротких массивах я бы пошел с принятым решением, используя array_column , или если вы уверены, что материал есть, есть эта настройка array_column :

 // Transform the records into keypairs $keypairs = array_column($records, 'value', 'key'); 

Теперь клавиши [ширина => 900, материал => бумага, …], поэтому:

 $material = $keypairs['material']; 

Я бы добавил array_key_exists чтобы быть уверенным. Это сохраняет array_search (не такое большое преимущество, но вы можете использовать объект keypair).

Если вам нужно именно это одно значение и ничего больше, производительность в порядке, а массив большой, я бы не выбрал идею поиска «материала»: «внутри JSON в виде строки с strpos , даже если это запах кода.

Если это json-текст, который вы указали в комментариях, мой совет – это регулярное совпадение.

Это найдет «ключевой материал» и «значение» и соответствует значению стоимости.
Он работает с небольшим образцом, но вы должны попробовать его на большей строке.

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

Вы можете использовать комбинацию array_search и array_column, поэтому нет необходимости использовать цикл

Рабочая демонстрация : 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']; 

Вывод

 paper