2015-07-13 3 views
1

Я пытаюсь написать фрагмент, который принимает многомерный массив и вставляет некоторые ключи на том же уровне, где найден именованный ключ поиска. Мне не нужно полагаться на структуру массива (но будет не более 5 уровней) Я не могу использовать прохождение по ссылке, поэтому традиционная повторяющаяся функция не поможет этому подходу.Итерация многомерного массива рекурсивно и возврат той же структуры массива и вставка нового ключа/значений в PHP

У меня есть 2 варианта: SPL или рекурсии, что повторно создает массив и изменяет его по пути

с SPL я не могу показаться, чтобы вставить новое значение ..

  $a= new \ArrayObject($priceConfig); 
      $array = new \RecursiveArrayIterator($a); 
      $iterator = new \RecursiveIteratorIterator($array, \RecursiveIteratorIterator::SELF_FIRST); 
      foreach ($iterator as $key => $value) { 
       if (is_array($value) && $key == 'prices') { 
        $iterator->offsetSet('myPrice',['amount'=>'1.00']); 
       } 
      } 

      print_r($a->getArrayCopy()); 

Он не будет вставлять новый ключ на желаемом уровне, но он выполняет цикл через массив. Что мне не хватает?

рекурсивная функция, которая реконструирует массив и вставить новые значения в моем ключе поиска в вложенных работах массива, но я хотел бы использовать итераторы, чтобы сделать это ..

   function recursive($input, $searchKey, $key=null) { 
       $holder = array(); 
       if(is_array($input)) { 
        foreach($input as $key => $el) { 
         if (is_array($el)) { 
          $holder[$key] = recursive($el, $searchKey, $key); 
          if ($key == $searchKey) { 
           $holder[$key]['inertedPrice'] = "value"; 
          } 
         } else { 
          $holder[$key] = $el; 
         } 
        } 
       } 
       return $holder; 
      } 

ВХОДОМ (всегда будет иметь некоторые "ключ цены и структуры на уровне X")

[1] => Array 
     (
      [1] => Array 
       (
        [prices] => Array 
         (
          [onePrice] => Array([amount] => 10) 
          [finalPrice] => Array ([amount] => 10) 
         ) 
        [key1] => value2 
        [key2] => value2 
       ) 

      [2] => Array 
       (
        [prices] => Array 
         (
          [otherPrice] => Array([amount] => 20) 
          [finalPrice] => Array([amount] => 20) 
         ) 
        [key] => value 
       ) 
     ) 
) 

Выходной

[1] => Array 
    (
     [1] => Array 
      (
       [prices] => Array 
        (
         [onePrice] => Array([amount] => 10) 
         [finalPrice] => Array ([amount] => 10) 
         [INSERTEDPrice] => Array([amount] => value) 
        ) 
       [key1] => value2 
       [key2] => value2 
      ) 

     [2] => Array 
      (
       [prices] => Array 
        (
         [otherPrice] => Array([amount] => 20) 
         [finalPrice] => Array([amount] => 20) 
         [INSERTEDPrice] => Array([amount] =>) 
        ) 
       [key] => value 
      ) 
    ) 

)

+0

Пожалуйста, включите образец ввода и вывода, чтобы мы могли лучше понять вопрос. – erisco

+0

добавил желаемый результат и предоставил вход – PartySoft

ответ

1

Вы могли бы подойти к решению проблемы, используя основные инструменты, такие как цикл просмотр и рекурсию довольно легко. Вот такое решение.

function mergeWithKey($targetKey, $new, array $array) { 
    foreach ($array as $key => $value) { 
    if ($key === $targetKey) { 
     $array[$key] = array_merge($array[$key], $new); 
    } 
    elseif (is_array($value)) { 
     $array[$key] = mergeWithKey($targetKey, $new, $value); 
    } 
    } 
    return $array; 
} 

// Example 
$output = mergeWithKey('prices', array('INSERTEDPrice' => 'value'), $input); 

Просто, как мы перебрать массив, если мы находим ключ мы ищем, то мы сливаемся в новой цене. Если вместо этого мы найдем суб-массив, мы объединим новую цену в этот под-массив.

Я приложил некоторое усилие, чтобы обобщить функцию, сохранив ключ «цены» в качестве параметра. Вероятно, это еще и неуловимая функция, которая вряд ли увидит повторное использование.

С помощью пары общих алгоритмов вы можете очень хорошо взломать эту функцию, и бонус - вы можете повторно использовать алгоритмы. Один из них состоит в том, чтобы сопоставить массив с ключом и значением, а другой - сгладить 2D-массив в 1D-массив.

function arrayMapWithKey(callable $f, array $array) { 
    $out = array(); 
    foreach ($array as $key => $value) { 
    $out[$key] = $f($key, $value); 
    } 
    return $out; 
} 

function concat(array $array) { 
    if (empty($array)) { 
    return array(); 
    } 
    else { 
    return call_user_func_array('array_merge', $array); 
    } 
} 

Эти определения позволяют вам написать альтернативное решение.

function addPrice($name, $price, $data) { 
    return concat(arrayMapWithKey(
    function ($k, $v) use ($name, $price) { 
     if ($k === 'prices') { 
     return array($k => array_merge($v, array($name => $price))); 
     } 
     elseif (is_array($v)) { 
     return array($k => addPrice($name, $price, $v)); 
     } 
     else { 
     return array($k => $v); 
     } 
    }, 
    $data 
)); 
} 

Другая формулировка для arrayMapWithKey является вместо копирования ключей со значением, а затем с помощью обычного array_map.

function arrayWithKeys(array $array) { 
    $out = array(); 
    foreach ($array as $key => $value) { 
    // in PHP arrays are often used as tuples, 
    // and here we have a 2-tuple. 
    $out[] = array($key, $value); 
    } 
    return $out; 
} 
+0

. Я собираюсь выбрать ваш ответ, потому что он более полный, мне тоже нравится ответ SPL, больше OOP и Alghoritms – PartySoft

1

Вы можете сделать это с помощью итераторов, расширяя RecursiveArrayIterator с пользовательской логикой итератора:

class Foo extends RecursiveArrayIterator 
{ 
    public function getChildren() 
    { 
     if ($this->key() == 'prices') { 
      return new self(array_merge($this->current(), ['foo' => 'bar'])); 
     } else { 
      return parent::getChildren(); 
     } 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^