2010-02-03 63 views
2

我有一個數組結構類似:如何過濾一個數組,以刪除父母等於零的孩子?

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

,我需要除去所有的「項目」鍵具有值零,並且如果項目沒有孩子的,刪除整個塊。

所以,過濾該數組後,我應該有:

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(這個作品很好tryed - 但是 - 犯規讓我刪除回調的關鍵函數..)沒有成功..

我有解構和重新構建一個新的數組,或者我缺少array_ *函數的正確使用嗎?

回答

4
$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 
1

我看不到的方式與array_walk_recursive做到這一點,所以只會像這樣的東西去:

/** 
* 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而另一個去除空的子元素則移除一個元素。這有不得不遍歷數組兩次的缺點。

如果您傳遞大量數據,轉換爲使用引用的函數應該不會太難。

2

好的,這是現在爲您的數組定製的。不要指望它與任意陣列結構的工作:

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

當數組在迭代,所有的元素被傳遞到的ItemFilterIteratoraccept()方法,它會檢查當前元素關鍵是數字。這僅適用於項目中的頂級元素和元素。如果當前元素是一個數組,則檢查是否存在具有鍵項目的元素,並且如果子項的 sum大於零。如果不是,則跳過迭代中的元素。如果它不是數組,但是數字和值爲零,則假定我們在項目內,並跳過這些元素。

你使用這樣的:

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

這是一個有趣的練習:)

更多SplIterators:

+0

+1它完美,謝謝!但它對我的實際需要看起來有點矯枉過正..我會用捅的解決方案 – Strae 2010-02-03 11:42:28

相關問題