php - 深度搜索数组数组并仅返回匹配元素

时间:2017-06-28 13:45:56

标签: php arrays

我正在寻找php中的解决方案,如此问题的接受答案所述:

javascript - return parent with only child that matches given search string in array of objects with nested object

请在下面找到代码:

<?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在线,修改它以返回整个匹配元素。它以递归方式搜索数组并返回匹配项。

例如,如代码中所示,如果我搜索字符串&#39; Oracle&#39;,它应该返回一个数组,其中一个项目在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,它应该返回如下:

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

)

如何在嵌套数组搜索中将匹配的子项与父项一起返回?

4 个答案:

答案 0 :(得分:3)

试试这段代码。

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

答案 1 :(得分: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);
}

确实

  1. 装饰数组以搜索 RecursiveArrayIterator
  2. 通过 RecursiveIteratorIterator 装饰仅用于叶子遍历的数组迭代器。
  3. 在所有叶子值上应用搜索(再次作为装饰器)。
  4. 其余的是foreach搜索并输出示范值。
  5. 并输出:

    string(14) "HP BL460C GEN8"
    string(14) "HP BL460C GEN8"
    

    搜索有效地设置在三行代码中。

    并非全部,因为在foreach内部我们仍然拥有装饰迭代的上下文,您不仅可以访问当前值,还可以访问三个级别, parent 你想回来:

    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的参赛人数的微妙差异,即一个而不是之前的两个。

答案 2 :(得分:1)

<?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>";

答案 3 :(得分:-1)

这应该可以解决问题。

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