Каков наилучший способ сглаживания массива с несколькими листовыми узлами, чтобы каждый полный путь к листу был отдельным возвратом?
array("Object"=>array("Properties"=>array(1, 2)));
уступить
Я могу сгладить Object.Properties.1, но 2 не обрабатывается с рекурсивной функцией:
function flattenArray($prefix, $array) { $result = array(); foreach ($array as $key => $value) { if (is_array($value)) $result = array_merge($result, flattenArray($prefix . $key . '.', $value)); else $result[$prefix . $key] = $value; } return $result; }
Я предполагаю, что сверху вниз не будет работать при прогнозировании нескольких листовых узлов, поэтому либо потребуется какой-то тип обработки снизу вверх, либо способ скопировать массив для каждого листа и процесса (хотя это кажется полностью неэффективным)
function flatten(array $data, $separator = '.') { $result = array(); $stack = array(); $path = null; reset($data); while (!empty($data)) { $key = key($data); $element = $data[$key]; unset($data[$key]); if (is_array($element)) { if (!empty($data)) { $stack[] = array($data, $path); } $data = $element; $path .= $key . $separator; } else { $result[$path . $key] = $element; } if (empty($data) && !empty($stack)) { list($data, $path) = array_pop($stack); } } return $result; } var_dump(flatten(array("Object"=>array("Properties"=>array(1, 2)))));
неfunction flatten(array $data, $separator = '.') { $result = array(); $stack = array(); $path = null; reset($data); while (!empty($data)) { $key = key($data); $element = $data[$key]; unset($data[$key]); if (is_array($element)) { if (!empty($data)) { $stack[] = array($data, $path); } $data = $element; $path .= $key . $separator; } else { $result[$path . $key] = $element; } if (empty($data) && !empty($stack)) { list($data, $path) = array_pop($stack); } } return $result; } var_dump(flatten(array("Object"=>array("Properties"=>array(1, 2)))));
Вывод:
array(2) { ["Object.Properties.0"]=> int(1) ["Object.Properties.1"]=> int(2) }
Используйте функцию flatMapAssoc () из Kdyby Framework :
$flattened= array(); flatMapAssoc($array, function ($value, $keys) use (&$flattened) { $flattened[implode('.', $keys)] = $value; }); /** * @param array|\Traversable $array * @param callable $callback * @return array */ function flatMapAssoc($array, $callback) { $callback = callback($callback); $result = array(); $walker = function ($array, $keys = array()) use (&$walker, &$result, $callback) { foreach ($array as $key => $value) { $currentKeys = $keys + array(count($keys) => $key); if (is_array($value)) { $walker($value, $currentKeys); continue; } $result[] = $callback($value, $currentKeys); } return $result; }; return $walker($array); }
Я бы использовал функцию-оболочку, чтобы скрыть детали реализации (параметр префикса) и добавил ветку if для проверки пустых массивов. Наконец, в случае простого листа вы должны использовать переменную $value
а не $key
.
$x = array("Object"=>array("Properties"=>array(1, 2), "test"=>array(), "post")); function flatten ($array) { return flattenArray('',$array); } function flattenArray($prefix, $array) { $result = array(); foreach ($array as $key => $value) { if (is_array($value)) { if(count($value)) { $result = array_merge($result, flattenArray($prefix."$key.", $value)); } else { $result[] = "$prefix$key"; } } else { $result[] = "$prefix$value"; } } return $result; } echo join("\n", flatten($x));
Если вы хотите имитировать древовидную структуру, возможно, вы можете использовать другую структуру массива. Что-то вроде этого:
$y = array ("Object", array("Properties", 1, 2), "test", "post" );
и flattenArray становится:
function flattenArray($prefix, $array) { $result = array(); $prefix .=array_shift($array).'.'; foreach ($array as $value) { if (is_array($value)) { $result = array_merge($result, flattenArray($prefix, $value)); } else { $result[] = "$prefix$value"; } } return $result; }