Как выровнять многомерный массив?

Возможно ли в PHP сгладить (двух- или многомерный) массив без использования рекурсии или ссылок?

Меня интересуют только значения, поэтому ключи можно игнорировать, я думаю, что array_map() а также array_values(),

207

Решение

Вы можете использовать Стандартная библиотека PHP (SPL) «скрыть» рекурсию.

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));
foreach($it as $v) {
echo $v, " ";
}

печать

1 2 3 4 5 6 7 8 9
233

Другие решения

По состоянию на PHP 5.3 самое короткое решение кажется array_walk_recursive() с новым синтаксисом замыканий:

function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
257

Решение для двумерного массива

Пожалуйста, попробуйте это:

$array  = your array

$result = call_user_func_array('array_merge', $array);

echo "<pre>";
print_r($result);

РЕДАКТИРОВАТЬ: 21 августа 13

Вот решение, которое работает для многомерного массива:

function array_flatten($array) {
$return = array();
foreach ($array as $key => $value) {
if (is_array($value)){
$return = array_merge($return, array_flatten($value));
} else {
$return[$key] = $value;
}
}

return $return;
}

$array  = Your array

$result = array_flatten($array);

echo "<pre>";
print_r($result);

Ref: http://php.net/manual/en/function.call-user-func-array.php

73

Чтобы сгладить без рекурсии (как вы просили), вы можете использовать стек. Естественно, вы можете поместить это в функцию своего собственного как array_flatten, Ниже приведена версия, которая работает без ключей:

function array_flatten(array $array)
{
$flat = array(); // initialize return array
$stack = array_values($array); // initialize stack
while($stack) // process stack until done
{
$value = array_shift($stack);
if (is_array($value)) // a value to further process
{
$stack = array_merge(array_values($value), $stack);
}
else // a value to take
{
$flat[] = $value;
}
}
return $flat;
}

Элементы обрабатываются в их порядке. Поскольку подэлементы будут перемещены поверх стека, они будут обработаны следующими.

Также можно принять во внимание ключи, однако вам потребуется другая стратегия для обработки стека. Это необходимо, потому что вам нужно иметь дело с возможными дублирующимися ключами в подмассивах. Подобный ответ в связанном вопросе: PHP Walk через многомерный массив с сохранением ключей

Я не совсем уверен, но я проверял это в прошлом: RecurisiveIterator действительно использует рекурсию, так что это зависит от того, что вам действительно нужно. Должна быть возможность создать рекурсивный итератор также на основе стеков:

foreach(new FlatRecursiveArrayIterator($array) as $key => $value)
{
echo "** ($key) $value\n";
}

демонстрация

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

23

Использует рекурсию. Надеюсь, увидев, насколько это не сложно, ваш страх рекурсии рассеется, как только вы увидите, как это не сложно.

function flatten($array) {
if (!is_array($array)) {
// nothing to do if it's not an array
return array($array);
}

$result = array();
foreach ($array as $value) {
// explode the sub-array, and add the parts
$result = array_merge($result, flatten($value));
}

return $result;
}$arr = array('foo', array('nobody', 'expects', array('another', 'level'), 'the', 'Spanish', 'Inquisition'), 'bar');
echo '<ul>';
foreach (flatten($arr) as $value) {
echo '<li>', $value, '</li>';
}
echo '<ul>';

Выход:

<ul><li>foo</li><li>nobody</li><li>expects</li><li>another</li><li>level</li><li>the</li><li>Spanish</li><li>Inquisition</li><li>bar</li><ul>
17

Просто подумал, что укажу, что это фолд, поэтому можно использовать array_reduce:

array_reduce($my_array, 'array_merge', array());

РЕДАКТИРОВАТЬ: Обратите внимание, что это может быть составлено, чтобы сгладить любое количество уровней. Мы можем сделать это несколькими способами:

// Reduces one level
$concat   = function($x) { return array_reduce($x, 'array_merge', array()); };

// We can compose $concat with itself $n times, then apply it to $x
// This can overflow the stack for large $n
$compose  = function($f, $g) {
return function($x) use ($f, $g) { return $f($g($x)); };
};
$identity = function($x) { return $x; };
$flattenA = function($n) use ($compose, $identity, $concat) {
return  function($x) use ($compose, $identity, $concat, $n) {
return ($n === 0)? $x
: call_user_func(array_reduce(array_fill(0, $n, $concat),
$compose,
$identity),
$x);
};
};

// We can iteratively apply $concat to $x, $n times
$uncurriedFlip     = function($f) {
return  function($a, $b) use ($f) {
return $f($b, $a);
};
};
$iterate  = function($f) use ($uncurriedFlip) {
return  function($n) use ($uncurriedFlip, $f) {
return  function($x) use ($uncurriedFlip, $f, $n) {
return ($n === 0)? $x
: array_reduce(array_fill(0, $n, $f),
$uncurriedFlip('call_user_func'),
$x);
}; };
};
$flattenB = $iterate($concat);

// Example usage:
$apply    = function($f, $x) {
return $f($x);
};
$curriedFlip = function($f) {
return  function($a) use ($f) {
return  function($b) use ($f, $a) {
return $f($b, $a);
}; };
};

var_dump(
array_map(
call_user_func($curriedFlip($apply),
array(array(array('A', 'B', 'C'),
array('D')),
array(array(),
array('E')))),
array($flattenA(2), $flattenB(2))));

Конечно, мы могли бы также использовать циклы, но вопрос требует использования комбинаторной функции по аналогии с массивами array_map или array_values.

16

прямой а также Один лайнер ответ.

function flatten_array(array $array)
{
return iterator_to_array(
new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)));
}

Использование:

$array = [
'name' => 'Allen Linatoc',
'profile' => [
'age' => 21,
'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
]
];

print_r( flatten_array($array) );

Выход (в PsySH):

Array
(
[name] => Allen Linatoc
[age] => 21
[0] => Call of Duty
[1] => Titanfall
[2] => Far Cry
)

Теперь вам решать, как вы будете обращаться с ключами. ура


РЕДАКТИРОВАТЬ (2017-03-01)

квотирование Найджел Олдертонбеспокойство / проблема:

Просто чтобы уточнить, это сохраняет ключи (даже числовые), поэтому значения с одинаковым ключом теряются. Например $array = ['a',['b','c']] становится Array ([0] => b, [1] => c ), 'a' потерян, потому что 'b' также имеет ключ 0

квотирование Svishответ:

Просто добавьте false в качестве второго параметра ($use_keys) к iterator_to_array вызов

14

В PHP 5.6 и выше вы можете сгладить двумерные массивы с помощью array_merge после распаковки внешнего массива с ... оператор. Код прост и понятен.

$a = [[10, 20], [30, 40]];
$b = [["x" => "X", "y" => "Y"], ["p" => "P", "q" => "Q"]];

print_r(array_merge(...$a));
print_r(array_merge(...$b));

Array
(
[0] => 10
[1] => 20
[2] => 30
[3] => 40
)
Array
(
[x] => X
[y] => Y
[p] => P
[q] => Q
)

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

$c = ["a" => ["x" => "X", "y" => "Y"], "b" => ["p" => "P", "q" => "Q"]];
print_r(array_merge(...array_values($c)));

Array
(
[x] => X
[y] => Y
[p] => P
[q] => Q
)
13
По вопросам рекламы [email protected]