代码之家  ›  专栏  ›  技术社区  ›  Strae

如何筛选数组以删除子级为零的父级?

  •  2
  • Strae  · 技术社区  · 16 年前

    我有一个数组的结构如下:

    $something = array(
        0 => array(
            'label' => 'Foo',
            'items' => array(
                '123' => 4,
                '124' => 0,
            )
        ),
        1 => array(
            'label' => 'Bar',
            'items' => array(
                '125' => 5,
                '126' => 1,
            )
        ),
        2 => array(
            'label' => 'Baz',
            'items' => array(
                '127' => 0,
                '128' => 0,
            )
        )
    );
    

    我需要删除所有值为零的“items”键,如果一个项没有子项,则删除整个块。

    所以,在过滤了这个数组之后,我应该有:

    array(2){
        [0]=>
        array(2) {
            ["label"]=> "Foo"
            ["items"]=>
                array(1) {
                    [123]=> 4
                }
        }
        [1]=>
        array(2) {
        ["label"]=> "Bar"
        ["items"]=>
            array(2) {
                [125]=> 5
                [126]=> 1
            }
        }
    }
    

    我尝试过使用array_filter、array_walk和array_walk_recursive(这一个很好-但是-不允许我删除回调函数中的键..)但没有成功。

    我是要在新的一个数组中解构和重建,还是缺少对数组函数的正确使用?

    3 回复  |  直到 16 年前
        1
  •  4
  •   poke    16 年前
    $something = array( .. ); // as defined above
    
    for ( $i = 0, $iMax = count( $something ); $i < $iMax; $i++ )
    {
        foreach ( $something[$i]['items'] as $key => $value )
        {
            if ( !$value )
                unset( $something[$i]['items'][$key] );
        }
    
        if ( count( $something[$i]['items'] ) == 0 )
            unset( $something[$i] );
    }
    $something = array_values( $something ); // reset indices
    
        2
  •  2
  •   Gordon Haim Evgi    16 年前

    好的,这是为您的阵列定制的。不要期望它与任意数组结构一起工作:

    class ItemFilterIterator extends RecursiveFilterIterator
    {
        public function accept()
        {
            if(is_numeric($this->key()) && is_array($this->current())) {
                if(array_key_exists('items', $this->current())) {
                    $items = $this->current();
                    return array_sum($items['items']) > 0;
                }
            } elseif(is_numeric($this->key()) && $this->current() === 0 ) {
                return false;
            }
            return true;
        }
    }
    

    迭代数组时,所有元素都传递给 accept() 方法 ItemFilterIterator ,这将检查 钥匙 现在的 元素是数字。这仅适用于顶级元素和 项目 . 如果当前元素是数组,请检查是否有带键的元素 项目 如果孩子们 价值观 和大于零。如果不是,跳过迭代中的元素。如果它不是数组,但数值为零,则假定我们在 项目 也跳过这些元素。

    你这样使用它:

    $iterator = new RecursiveIteratorIterator(
                    new ItemFilterIterator(
                        new RecursiveArrayIterator($something)));
    
    foreach($iterator as $key => $value) {
        echo $key, '--', $value, PHP_EOL; // or whatever else you want to do here
    }
    

    这是一个有趣的练习:)

    有关拆分器的详细信息:

        3
  •  1
  •   Yacoby    16 年前

    我看不出用数组“walk”递归来完成它的方法,所以只需要这样做:

    /**
     * Removes values from an array if the callback function is true.
     * Removes empty child arrays
     */
    function array_remove_recursive(array $haystack, $f){
        if ( empty($haystack) ){
            return $haystack;
        }
        foreach ( $haystack as $key => $val ){
            if ( is_array($val){
                $haystack[$key] = array_remove_recursive($val);
                if ( empty($haystack[$key]){
                    unset($haystack[$key]);
                }
            }elseif ( $f($val) === true ){
                unset($haystack[$key]);
            }
        }
        return $haystack;
    }
    

    基于“每个函数只做一件事,一件事”的原则,最好将它分成两个函数,一个函数返回true时移除元素,另一个函数移除空的子元素。这样做的缺点是必须遍历数组两次。

    如果传递了大量的数据,那么转换为使用引用的函数就不太难了。

    推荐文章