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' => 'valay@xyz.com', ), 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' => 'valay@xyz.com', ) ) ); 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] => valay@xyz.com ) ) 

Если я ищу строку HP BL460C GEN8 , она должна вернуться, как 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] => valay@xyz.com ) [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' => 'valay@xyz.com' ) ) 

Как вернуть соответствующий дочерний элемент с родителем при поиске вложенных массивов?

Solutions Collecting From Web of "php – глубокий массив поиска массивов и возвращает только соответствующие элементы"

Попробуйте этот код.

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

Чтобы глубоко искать только листовые узлы, это прямолинейно с рекурсивной итерацией через 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); } 

Оно делает

  1. Украсьте массив для поиска в качестве рекурсивного массива.
  2. Украсьте итератор массива для обхода листа только через RecursiveIteratorIterator .
  3. Примените поиск (снова как декоратор) на всех значениях листа.
  4. Остальное – для поиска и вывода значений для демонстрации.

И выйдет:

 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] => valay@xyz.com ) 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] => valay@xyz.com ) 

Но что, если вы можете захотеть уменьшить массив 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] => valay@xyz.com ) 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] => valay@xyz.com ) 

Обратите внимание на тонкие различия в первом совпадении количества записей в asset_info , то есть вместо двух предыдущих.

 <?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' => 'valay@xyz.com', ), 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' => 'valay@xyz.com', ) ) ); 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>"; с <?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' => 'valay@xyz.com', ), 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' => 'valay@xyz.com', ) ) ); 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>"; 

Это должно сделать трюк.

 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; } не 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; } 

Edit: Предполагается, что вы вызываете это getParentStackComplete('Oracle', $items['tableData'])