Nasıl sıfıra eşit çocuk ile anne kaldırmak için bir dizi filtre?

2 Cevap php

i gibi yapılandırılmış bir dizi var:

$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,
        )
    )
);

Ve ben sıfır değerine sahip tüm 'ürün' tuşuna kaldırmak gerekir, ve bir ürün hiçbir oğul varsa, tüm bloğu kaldırmak.

Yani, bu diziyi süzüldükten sonra, ben sahip olmalıdır:

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

Ben array_filter kullanarak uğraş verdik, array_walk ve (bu iyi çalışıyor - ama - bana geri arama işlevi anahtarlarını kaldırmak için izin vermez ..) array_walk_recursive başarı olmadan ..

I yapısızlaştırmak ve yeniden yeni bir dizi, ya da ben array_ * fonksiyonların doğru kullanımını eksik var?

2 Cevap

Tamam, bu özel şimdi dizi için hazırlanmıştır. Bu keyfi dizi yapıları ile çalışmak için beklemeyin:

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

Dizinin yineleme, tüm elemanları kontrol edecek ItemFilterIterator ve accept() yöntem geçirilen halinde key current bölgesinin eleman sayısal. Bu yalnızca items içindeki üst düzeyde elemanları ve elemanları için de geçerlidir. Geçerli öğe bir dizi ise çocuk values toplamı sıfırdan büyükse, items tuşu ile bir unsur olup olmadığını kontrol edin ve. Değilse, tekrarında elemanı atlayın. Bir dizi, ama sayısal değildir ve sıfır değeri varsa, biz items içinde olduğunu varsayıyorum ve de bu unsurları atlayın.

Bu gibi kullanabilirsiniz:

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

Bu eğlenceli bir egzersiz oldu :)

SplIterators Daha:

Ben array_walk_recursive ile bunu yapmak için bir yol göremiyorum, yani sadece böyle bir şey ile devam ediyorum:

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

Dayanarak "Her fonksiyon bir şey ve tek şey gelmez", Bu işlev boş çocukları kaldırmak için doğru ve diğer dönerse bir öğe kaldırmak için iki fonksiyon, bir bölmek muhtemelen tercih ilkedir. Bu iki dizinin üzerinde yürümek zorunda dezavantajı vardır.

Bu etrafında bir çok veri geçen olsaydı başvuruları kullanan bir fonksiyonu haline dönüştürmek çok zor olmamalı.