Поскольку у меня есть массив:
$array = array( 'a' => array( 'b' => array( 'c' => 'hello', ), ), 'd' => array( 'e' => array( 'f' => 'world', ), ), );
Я хочу «сгладить» его в один размерный поиск ссылок, объединяя ключи с разделителем ( в случае этого примера – косую черту )
Выполнение var_dump()
на успешном выходе даст: ( обратите внимание на все ссылки )
array(6) { ["a"]=> &array(1) { ["b"]=> &array(1) { ["c"]=> &string(5) "hello" } } ["a/b"]=> &array(1) { ["c"]=> &string(5) "hello" } ["a/b/c"]=> &string(5) "hello" ["d"]=> &array(1) { ["e"]=> &array(1) { ["f"]=> &string(5) "world" } } ["d/e"]=> &array(1) { ["f"]=> &string(5) "world" } ["d/e/f"]=> &string(5) "world" } array(2) { ["a"]=> &array(1) { ["b"]=> &array(1) { ["c"]=> &string(5) "hello" } } ["d"]=> &array(1) { ["e"]=> &array(1) { ["f"]=> &string(5) "world" } } }
Как бы то ни было, я использую это:
function build_lookup(&$array, $keys = array()){ $lookup = array(); foreach($array as $key => &$value){ $path = array_merge($keys, (Array) $key); $lookup[implode('/', $path)] = &$value; if(is_array($value)){ $lookup = array_merge($lookup, build_lookup($value, $path)); } } return $lookup; }
Тем не менее, я пытаюсь улучшить его, удалив элемент рекурсии ( переход на метод stack / pop ). Проблема с этим заключается в сохранении ссылок, поскольку типичный подход рекурсии к нерекурсии:
$stack = $input; while(!empty($stack)){ $current = array_pop($stack); // do stuff and push to stack; }
в$stack = $input; while(!empty($stack)){ $current = array_pop($stack); // do stuff and push to stack; }
… не соответствует рекомендациям.
Я видел несколько похожих вопросов / ответов на SO, хотя ни одно из них не соответствовало ссылкам ( поскольку это не было намерением апеллянта )
Есть ли лучший ( читаемый быстрее ) подход здесь?
Возможное решение ( спасибо @chris ):
/** * * @return array */ public function get_lookup_array() { $stack = $lookup = array(); try { foreach($this->_array as $key => &$value) { $stack[$key] = &$value; } while(!empty($stack)) { $path = key($stack); $lookup[$path] = &$stack[$path]; if(is_array($lookup[$path])) { foreach($lookup[$path] as $key => &$value) { $stack[$path . $this->_separator . $key] = &$value; } } unset($stack[$path]); } } catch(\Exception $exception) { return false; } return $lookup; }
в/** * * @return array */ public function get_lookup_array() { $stack = $lookup = array(); try { foreach($this->_array as $key => &$value) { $stack[$key] = &$value; } while(!empty($stack)) { $path = key($stack); $lookup[$path] = &$stack[$path]; if(is_array($lookup[$path])) { foreach($lookup[$path] as $key => &$value) { $stack[$path . $this->_separator . $key] = &$value; } } unset($stack[$path]); } } catch(\Exception $exception) { return false; } return $lookup; }
с/** * * @return array */ public function get_lookup_array() { $stack = $lookup = array(); try { foreach($this->_array as $key => &$value) { $stack[$key] = &$value; } while(!empty($stack)) { $path = key($stack); $lookup[$path] = &$stack[$path]; if(is_array($lookup[$path])) { foreach($lookup[$path] as $key => &$value) { $stack[$path . $this->_separator . $key] = &$value; } } unset($stack[$path]); } } catch(\Exception $exception) { return false; } return $lookup; }
header('content-type:text/plain'); $arr = array( 'a' => array( 'b' => array( 'c' => 'hello', ), ), 'd' => array( 'e' => array( 'f' => 'world', ), ), ); //prime the stack using our format $stack = array(); foreach ($arr as $k => &$v) { $stack[] = array( 'keyPath' => array($k), 'node' => &$v ); } $lookup = array(); while ($stack) { $frame = array_pop($stack); $lookup[join('/', $frame['keyPath'])] = &$frame['node']; if (is_array($frame['node'])) { foreach ($frame['node'] as $key => &$node) { $keyPath = array_merge($frame['keyPath'], array($key)); $stack[] = array( 'keyPath' => $keyPath, 'node' => &$node ); $lookup[join('/', $keyPath)] = &$node; } } } var_dump($lookup); // check functionality $lookup['a'] = 0; $lookup['d/e/f'] = 1; var_dump($arr);
В качестве альтернативы вы могли бы сделать такие вещи, чтобы получить функциональность reference / w array_pop
end($stack); $k = key($stack); $v = &$stack[$k]; unset($stack[$k]);
Это работает, потому что массивы php имеют элементы, упорядоченные по времени создания ключа. unset () удаляет ключ и, таким образом, сбрасывает время создания для этого ключа.