Php - глубокий массив поиска массивов и возвращает только соответствующие элементы
Я ищу решение в php
, как указано в принятом ответе на этот вопрос:
javascript - вернуть родительский элемент только с дочерним элементом, который соответствует заданной строке поиска в массиве объектов с вложенным объектом
Код ниже:
<?php
$items = array(
'tableData' => array
(
array
(
'booking_name' => 'abc/xyz/123',
'pdg' => 'assure',
'user_area' => 'es st1',
'release' => 'oss72',
'start_date' => '2017-06-20 00:00:00',
'end_date' => '2017-06-23 00:00:00',
'asset_info' => array
(
array
(
'status' => 10,
'manufacturer' => 'Oracle',
'model' => 'HP BL460C GEN8',
'hardware_color' => '#0066b3',
),
array
(
'status' => 11,
'manufacturer' => 'HP',
'model' => 'HP BL460C GEN81',
'hardware_color' => '#0066b3',
)
),
'full_name' => 'Valay Desai',
'email_address' => '[email protected]',
),
array
(
'booking_name' => 'abc/xyz/123',
'pdg' => 'enm',
'user_area' => 'es st',
'release' => 'oss72',
'start_date' => '2017-06-20 00:00:00',
'end_date' => '2017-06-23 00:00:00',
'asset_info' => array
(
array
(
'status' => 10,
'manufacturer' => 'HP',
'model' => 'HP BL460C GEN8',
'hardware_color' => '#0066b3',
)
),
'full_name' => 'Valay Desai',
'email_address' => '[email protected]',
)
)
);
function getParentStackComplete($child, $stack) {
$return = array();
foreach ($stack as $k => $v) {
if (is_array($v)) {
// If the current element of the array is an array, recurse it
// and capture the return stack
$stack = getParentStackComplete($child, $v);
// If the return stack is an array, add it to the return
if (is_array($stack) && !empty($stack)) {
$return[] = $v;
}
} else {
// Since we are not on an array, compare directly
if(strpos($v, $child) !== false){
// And if we match, stack it and return it
$return[] = $v;
}
}
}
// Return the stack
return empty($return) ? false: $return;
}
echo "<pre>";
print_r(getParentStackComplete('Oracle', $items['tableData']));
echo "</pre>";
?>
Этот код работает нормально. Я нашел функцию getParentStackComplete
онлайн, изменил ее, чтобы вернуть весь соответствующий элемент. Он ищет рекурсивно массив и возвращает соответствующие элементы.
Например, как указано в коде, если я ищу строку "Oracle", она должна вернуть массив с одним элементом, который имеет только один дочерний элемент (соответствующий элемент) в asset_info
. Результат, который я ищу, это:
Array
(
[0] => Array
(
[booking_name] => abc/xyz/123
[pdg] => assure
[user_area] => es st1
[release] => oss72
[start_date] => 2017-06-20 00:00:00
[end_date] => 2017-06-23 00:00:00
[asset_info] => Array
(
[0] => Array
(
[status] => 10
[manufacturer] => Oracle
[model] => HP BL460C GEN8
[hardware_color] => #0066b3
)
)
[full_name] => Valay Desai
[email_address] => [email protected]
)
)
Если я ищу строку HP BL460C GEN8
, она должна вернуться, как показано ниже:
Array
(
[0] => Array
(
[booking_name] => abc/xyz/123
[pdg] => assure
[user_area] => es st1
[release] => oss72
[start_date] => 2017-06-20 00:00:00
[end_date] => 2017-06-23 00:00:00
[asset_info] => Array
(
[0] => Array
(
[status] => 10
[manufacturer] => Oracle
[model] => HP BL460C GEN8
[hardware_color] => #0066b3
)
)
[full_name] => Valay Desai
[email_address] => [email protected]
)
[1] => Array
(
'booking_name' => 'abc/xyz/123',
'pdg' => 'enm',
'user_area' => 'es st',
'release' => 'oss72',
'start_date' => '2017-06-20 00:00:00',
'end_date' => '2017-06-23 00:00:00',
'asset_info' => array
(
array
(
'status' => 10,
'manufacturer' => 'HP',
'model' => 'HP BL460C GEN8',
'hardware_color' => '#0066b3',
)
),
'full_name' => 'Valay Desai',
'email_address' => '[email protected]'
)
)
Как вернуть соответствующий дочерний элемент с родителем при поиске вложенных массивов?
Ответы
Ответ 1
Попробуйте этот код.
function getParentStackComplete( $search, $stack ){
$results = array();
foreach( $stack as $item ){
if( is_array( $item ) ){
if( array_filter($item, function($var) use ($search) { return ( !is_array( $var ) )? stristr( $var, $search ): false; } ) ){
//echo 'test';
$results[] = $item;
continue;
}else if( array_key_exists('asset_info', $item) ){
$find_assets = array();
foreach( $item['asset_info'] as $k=>$v ){
//echo 'abc ';
if( is_array( $v ) && array_filter($v, function($var) use ($search) { return stristr($var, $search); }) ){
$find_assets[] = $v;
}
}
if( count( $find_assets ) ){
$temp = $item;
$temp['asset_info'] = $find_assets;
$results[] = $temp;
}
}
}
}
return $results;
}
Ответ 2
Чтобы глубоко искать только узлы листа, это прямо с рекурсивной итерацией через RecursiveIterator, ее RecursiveIteratorIterator обрабатывает только обход листа через RecursiveArrayIterator.
Чтобы сделать это видимым здесь небольшой пример поиска в ваших данных примера:
$iterator = new RecursiveArrayIterator($items['tableData']); # 1.
$leafs = new RecursiveIteratorIterator($iterator); # 2.
$search = new RegexIterator($leafs, sprintf('~^%s$~', preg_quote('HP BL460C GEN8', '~'))); # 3.
foreach ($search as $value) { # 4.
var_dump($value);
}
Он делает
- Украсьте массив для поиска как РекурсивныйArrayIterator.
- Украсьте итератор массива для обхода листа только через RecursiveIteratorIterator.
- Применить поиск (снова как декоратор) во всех значениях листа.
- Остальное -
foreach
поиск и вывод значений для демонстрации.
И выведет:
string(14) "HP BL460C GEN8"
string(14) "HP BL460C GEN8"
Поиск эффективно настраивается в трех строках кода.
И это не все, так как внутри foreach
мы все еще имеем контекст декорированной итерации, вы можете получить доступ не только к текущему значению, но и к тому, что три уровня вверх, родительский элемент, который вы хотите вернуть:
foreach ($search as $key => $value) {
$parentLevel = 0; # or for relative access: $leafs->getDepth() - 3
$parent = $leafs->getSubIterator($parentLevel)->current();
var_dump($parent);
}
Это приведет к вывозу всех родительских объектов, которые соответствовали поиску.
Это уже может ответить на ваш вопрос, поэтому давайте полностью покажем пример:
$search = function (array $array, string $term) {
$iterator = new RecursiveArrayIterator($array);
$leafs = new RecursiveIteratorIterator($iterator);
$search = new RegexIterator($leafs, sprintf('~^%s$~', preg_quote($term, '~')));
foreach ($search as $value) {
$parent = $leafs->getSubIterator(0)->current();
yield $parent;
}
};
$matches = $search($items['tableData'], 'HP BL460C GEN8');
foreach ($matches as $index => $match) {
echo $index + 1, ': ';
print_r($match);
}
И он выводит:
1: Array
(
[booking_name] => abc/xyz/123
[pdg] => assure
[user_area] => es st1
[release] => oss72
[start_date] => 2017-06-20 00:00:00
[end_date] => 2017-06-23 00:00:00
[asset_info] => Array
(
[0] => Array
(
[status] => 10
[manufacturer] => Oracle
[model] => HP BL460C GEN8
[hardware_color] => #0066b3
)
[1] => Array
(
[status] => 11
[manufacturer] => HP
[model] => HP BL460C GEN81
[hardware_color] => #0066b3
)
)
[full_name] => Valay Desai
[email_address] => [email protected]
)
2: Array
(
[booking_name] => abc/xyz/123
[pdg] => enm
[user_area] => es st
[release] => oss72
[start_date] => 2017-06-20 00:00:00
[end_date] => 2017-06-23 00:00:00
[asset_info] => Array
(
[0] => Array
(
[status] => 10
[manufacturer] => HP
[model] => HP BL460C GEN8
[hardware_color] => #0066b3
)
)
[full_name] => Valay Desai
[email_address] => [email protected]
)
Но что, если вы захотите уменьшить количество родительских массивов asset_info
, чтобы содержать только те совпадения, а не только все родители, содержащие совпадение. Если это так, для создания массива результатов, который будет содержать только те записи в asset_info
, которые будут соответствовать. Это требует отслеживания согласованных родителей, чтобы к их результату можно было добавить совпадения asset_info
.
Поскольку для этого требуется обработать все согласованные активы одного и того же родителя, а затем предоставить этому родителю только эти соответствия. Таким образом, совпадения будут сгруппированы в их родителях, поэтому это своего рода функция агрегирования и, следовательно, имеет немного больше вещей для управления, поскольку необходимо отслеживать, имеет ли родитель все совпадения:
$search = function (array $array, string $term) {
$iterator = new RecursiveArrayIterator($array);
$leafs = new RecursiveIteratorIterator($iterator);
/* @var $search RecursiveIteratorIterator|RegexIterator - $search is a decorator of that type */
$search = new RegexIterator($leafs, sprintf('~^%s$~', preg_quote($term, '~')));
# initialize
$match = $lastId = null;
foreach ($search as $key => $value) {
$parentId = $search->getSubIterator(0)->key();
if ($lastId !== $parentId && $match) {
yield $match;
$match = null;
}
$lastId = $parentId;
if (empty($match)) {
# set match w/o asset_info as yet not matched
$match = $search->getSubIterator(0)->current();
$match['asset_info'] = [];
}
# add matched asset into the matched asset_info
$match['asset_info'][] = $search->getSubIterator(2)->current();
}
$match && yield $match;
};
$matches = $search($items['tableData'], 'HP BL460C GEN8');
foreach ($matches as $index => $match) {
echo $index + 1, ': ';
print_r($match);
}
Результат выводится в вашем случае:
1: Array
(
[booking_name] => abc/xyz/123
[pdg] => assure
[user_area] => es st1
[release] => oss72
[start_date] => 2017-06-20 00:00:00
[end_date] => 2017-06-23 00:00:00
[asset_info] => Array
(
[0] => Array
(
[status] => 10
[manufacturer] => Oracle
[model] => HP BL460C GEN8
[hardware_color] => #0066b3
)
)
[full_name] => Valay Desai
[email_address] => [email protected]
)
2: Array
(
[booking_name] => abc/xyz/123
[pdg] => enm
[user_area] => es st
[release] => oss72
[start_date] => 2017-06-20 00:00:00
[end_date] => 2017-06-23 00:00:00
[asset_info] => Array
(
[0] => Array
(
[status] => 10
[manufacturer] => HP
[model] => HP BL460C GEN8
[hardware_color] => #0066b3
)
)
[full_name] => Valay Desai
[email_address] => [email protected]
)
Обратите внимание на тонкие различия в первом совпадении числа записей в asset_info
, то есть вместо двух предыдущих.
Ответ 3
<?php
$items = array(
'tableData' => array
(
array
(
'booking_name' => 'abc/xyz/123',
'pdg' => 'assure',
'user_area' => 'es st1',
'release' => 'oss72',
'start_date' => '2017-06-20 00:00:00',
'end_date' => '2017-06-23 00:00:00',
'asset_info' => array
(
array
(
'status' => 10,
'manufacturer' => 'Oracle',
'model' => 'HP BL460C GEN8',
'hardware_color' => '#0066b3',
),
array
(
'status' => 11,
'manufacturer' => 'HP',
'model' => 'HP BL460C GEN81',
'hardware_color' => '#0066b3',
)
),
'full_name' => 'Valay Desai',
'email_address' => '[email protected]',
),
array
(
'booking_name' => 'abc/xyz/123',
'pdg' => 'enm',
'user_area' => 'es st',
'release' => 'oss72',
'start_date' => '2017-06-20 00:00:00',
'end_date' => '2017-06-23 00:00:00',
'asset_info' => array
(
array
(
'status' => 10,
'manufacturer' => 'HP',
'model' => 'HP BL460C GEN8',
'hardware_color' => '#0066b3',
)
),
'full_name' => 'Valay Desai',
'email_address' => '[email protected]',
)
)
);
function getParentStackComplete($child, $stack) {
$return = array();
$k=0;
foreach ($stack as $k => $v) {
if (is_array($v)) {
if (is_array($stack) && !empty($stack) && $k==0) {
unset($v['asset_info'][1]);
$return = $v;
}
} else {
if(strpos($v, $child) !== false){
$return[] = $v;
}
}
$k++;
}
return empty($return) ? false: $return;
}
echo "<pre>";
print_r(getParentStackComplete('Oracle', $items['tableData']));
echo "</pre>";
Ответ 4
Это должно сделать трюк.
function getParentStackComplete($search, $stack)
{
$results = [];
foreach ($stack as $i => $item) {
$results[] = $item;
$cache = $item['asset_info'];
$results[$i]['asset_info'] = [];
$found = false;
foreach ($cache as $asset) {
if (array_search($search, $asset) !== false) {
print('here' . "\n");
$found = true;
$results[$i]['asset_info'][] = $asset;
}
}
if (!$found) {
unset($results[$i]);
}
}
return $results;
}
Изменить: предполагается, что вы вызываете это как getParentStackComplete('Oracle', $items['tableData'])