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

Val*_*lay 1 php arrays

我正在寻找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>";


?>
Run Code Online (Sandbox Code Playgroud)

这段代码工作正常。我在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
        )

)
Run Code Online (Sandbox Code Playgroud)

如果我搜索 string 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'
       )

)
Run Code Online (Sandbox Code Playgroud)

如何在嵌套数组搜索中返回与父级匹配的子级?

hak*_*kre 5

要仅深度搜索叶节点,可以直接通过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);
}
Run Code Online (Sandbox Code Playgroud)

确实如此

  1. 将要搜索的数组装饰为RecursiveArrayIterator
  2. 通过RecursiveIteratorIterator装饰数组迭代器以进行仅叶遍历。
  3. 对所有叶值应用搜索(再次作为装饰器)。
  4. 剩下的就是foreach搜索并输出值进行演示。

并会输出:

string(14) "HP BL460C GEN8"
string(14) "HP BL460C GEN8"
Run Code Online (Sandbox Code Playgroud)

通过三行代码可以有效地设置搜索。

这还不是全部,因为在内部我们foreach仍然有装饰迭代的上下文,您不仅可以访问当前值,还可以访问上三层,即您想要返回的父级:

foreach ($search as $key => $value) {
    $parentLevel = 0; # or for relative access: $leafs->getDepth() - 3
    $parent = $leafs->getSubIterator($parentLevel)->current();
    var_dump($parent);
}
Run Code Online (Sandbox Code Playgroud)

这将输出与搜索匹配的所有父对象。

可能已经回答了您的问题,所以让我们完整地展示这个示例:

$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);
}
Run Code Online (Sandbox Code Playgroud)

它的输出:

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
)
Run Code Online (Sandbox Code Playgroud)

但是,如果您可能希望将parentsasset_info数组减少为仅包含这些匹配项,而不仅仅是包含匹配项的所有parents,该怎么办?如果是这样,则需要创建一个结果数组,其中仅包含asset_info匹配条目中的那些条目。这需要跟踪匹配的父母,以便asset_info可以将 matches 添加到他们的结果中。

因为这需要处理同一父级的所有匹配资产,然后仅向该父级提供这些匹配项。因此,匹配将在其父级中分组,因此这是一种聚合函数,因此需要管理更多的事情,因为它需要跟踪父级是否已经拥有所有匹配:

$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);
}
Run Code Online (Sandbox Code Playgroud)

在您的情况下,输出给出:

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
)
Run Code Online (Sandbox Code Playgroud)

请注意第一个匹配项中条目数量的细微差别asset_info,即一个而不是之前的两个。


Man*_*ish 5

试试这个代码。

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;
}
Run Code Online (Sandbox Code Playgroud)