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'])