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

259

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

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

Аликс Аксель
источник
17
Зачем избегать рекурсии?
JorenB
5
Dupe (в основном) stackoverflow.com/questions/526556/…
cletus
4
Вы не можете ничего сделать со всеми элементами произвольно глубоких массивов без рекурсии (вы можете замаскировать это как итерацию, но не картошку, потахто.) Если вы просто хотите избежать написания кода обработки рекурсии самостоятельно, используйте dk2.php.net/ manual / en / function.array-walk-recursive.php с обратным вызовом, который добавляет элемент к доступному массиву (используйте global, параметр userdata, поместите все это в класс и обратитесь к $ this и т. д.)
Майкл Мэдсен
@JorenB: Я бы хотел, чтобы реализация могла быть заархивирована.
Аликс Аксель
Взгляните на функцию сглаживания от Nspl . Вы также можете указать глубину с ним.
Игорь Бурлаченко

Ответы:

276

Вы можете использовать стандартную библиотеку 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 
VolkerK
источник
351
Я единственный, кто считает 'RecursiveIteratorIterator' глупым именем?
Ниламо
45
Это более «логично», чем «броско». Не все могут иметь фантастические имена, такие как JOGL, Knol или Azure :-)
VolkerK
7
Это не будет работать для пустых массивов, как дети. Они будут возвращены как родитель.
Хакре
45
iterator_to_array($it, false)избегает необходимости в foreach.
Аликс Аксель
3
Основываясь на том, что представили другие, я смог создать этого маленького помощника: function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }надеюсь, это поможет другим.
Майк С.
296

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

function flatten(array $array) {
    $return = array();
    array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
    return $return;
}
слишком много PHP
источник
33
если вам нужны ключи, функция flatten (array $ array) {$ return = array (); array_walk_recursive ($ array, функция ($ a, $ b) use (& $ return) {$ return [$ b] = $ a;}); возврат $ возврат; }
Брендон-Ван-Хейзен
Вы можете переписать это для использования с PHP 5.2?
Алекс
2
@Alex, к сожалению, вам нужен useсинтаксис для этой работы, array_walk_recursiveпоскольку он не будет принимать необязательный $userdataпараметр по ссылке
Тим Сегин,
1
Похоже, отлично работает для таких массивов -> ideone.com/DsmApP Но не для таких -> ideone.com/5Kltva Или это я?
Себастьян Пискорский,
2
@Sebastian Piskorski это потому, что ваши значения обрабатываются как ключи, поэтому, как только вы введете свою собственную пару ключ => значение в массив, значения массива в первой позиции индекса будут обрабатываться как ключи без значений, и потому что ключи имеют чтобы быть уникальным, когда совпадают два ключа, ваши значения добавляются к одному ключу. Простым решением было бы сначала отсортировать массив. Это поведение присуще PHP.
Мартын Шатт
92

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

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

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

Ссылка: http://php.net/manual/en/function.call-user-func-array.php

Прасант Бендра
источник
Спасибо, первый работал с массивом, который я получал от PDO, а другие решения - нет.
JAL
7
Это плохая стратегия. call_user_func_array('array_merge', [])(обратите внимание на пустой массив) возвращает ноль и вызывает предупреждение об ошибке php. Это отличное решение, если вы точно знаете, что ваш массив не будет пустым, но многие не могут этого сделать.
коза
ОП специально спрашивал о нерекурсивных решениях.
Электра
Ух, классная 2д квартира! Но для предотвращения уведомления просто используйте$result = $array ?call_user_func_array('array_merge', $array) : [];
Александр Гончаров
круто, но разве у тебя случайно нет функции-массива-дефлаттена?
FantomX1
65

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

array_merge(...$a);

Это работает и с коллекцией ассоциативных массивов.

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

Обновление: на основе комментария @MohamedGharib

Это выдаст ошибку, если внешний массив пуст, так как array_mergeбудет вызван с нулевыми аргументами. Этого можно избежать, добавив пустой массив в качестве первого аргумента.

array_merge([], ...$a);
Джойс Бабу
источник
1
Это работает ТОЛЬКО когда каждый элемент массива является массивом. Если массив содержит смешанные типы, такие как скаляры, произойдет ошибка.
Отей
@ Otheus Это потому, что вышеупомянутое решение не использует рекурсию. Как вы сказали, для этого требуется массив массивов. Но, с другой стороны, это должно быть намного быстрее, чем у других методов, поскольку у него нет дополнительных затрат на вызовы функций.
Джойс Бабу
2
Будет выдавать ошибку, если внешний массив пуст, его можно было бы избежать, если объединить с пустым массивомarray_merge([], ...$a);
Мохамед Гариб,
@MohamedGharib Хороший улов.
Джойс Бабу
Если вы используете ассоциативные массивы, вы можете проверить это решение stackoverflow.com/questions/40663687/…
alex
24

Чтобы сгладить без рекурсии (как вы просили), вы можете использовать стек . Естественно, вы можете поместить это в функцию своего собственного как 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 пройти через многомерный массив при сохранении ключей

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

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

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

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

hakre
источник
+1 за выдающуюся функцию array_flatten. Мне пришлось добавить if(!empty($value)){$flat[] = $value}внутри оператора else, чтобы предотвратить добавление пустого в массив результатов. Потрясающая функция!
Алекс Сарновски
19

Простой и однострочный ответ.

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 ответа «S:

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

Аллен Линаток
источник
Просто чтобы прояснить, это сохраняет ключи (даже числовые), поэтому значения с одинаковым ключом теряются. Например $array = ['a',['b','c']]становится Array ([0] => b, [1] => c ). Это 'a'потеряно, потому что 'b'также имеет ключ 0.
Найджел
1
@NigelAlderton Просто добавьте в falseкачестве второго параметра ( $use_keys) к iterator_to_arrayвызову.
Svish
18

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

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>
nilamo
источник
1
Я не боюсь рекурсии, я просто хочу изучить другие способы сделать то же самое.
Аликс Аксель
13
+1 за эту рекурсию: надеюсь, увидев, как она не сложна, ваш страх перед рекурсией рассеется, как только вы увидите, насколько она не сложна.
Tiberiu-Ionuț Stan
1
ОК, это по мне. Как это возможно, что ответ («Я не боюсь рекурсии») на три с половиной года старше (24 августа 2009 года), чем первоначальное утверждение («(...) ваш страх перед рекурсией рассеется (... ) "), сделано 5 февраля 13 года?
Трейдер
18

Просто подумал, что укажу, что это фолд, поэтому можно использовать 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.

Warbo
источник
Многомерный! = Двумерный.
Аликс Аксель
@atamur Это работает на PHP 5.3+. Как отмечено в журнале изменений для array_reduce, $ initial может быть только целым числом до 5.3, затем его можно было «смешивать» (т.
Е. Все, что
1
@AlixAxel Вы правы, что многомерный! = Двумерный, но это может быть составлено, чтобы сгладить любое количество уровней. Хорошим следствием составления сгибов является то, что они подчиняются фиксированному пределу; если у меня есть массив, вложенный в 5 уровней, я могу разделить foldего на 4 уровня, или fold . foldполучить 3 уровня, или fold . fold . fold2 уровня и т. д. Это также предотвращает скрытие ошибок; например. если я хочу сгладить массив 5D, но мне дан массив 4D, ошибка немедленно сработает.
Варбо
Я люблю это решение, для 2-мерных массивов. Идеально соответствует требованиям.
Том Оже
Я согласен, что ваше одноуровневое определение является лучшим ответом, но оно также чудесно и аккуратно. Однако я думаю, что вы неправильно назвали это $concat, я думаю, вы должны просто назвать это $flatten. array_mergeявляется php-эквивалентом concat. Я пытался получить array_concatдобавлен в качестве псевдонима array_merge.
icc97
9

Выравнивает только двухмерные массивы:

$arr = [1, 2, [3, 4]];
$arr = array_reduce($arr, function ($a, $b) {
     return array_merge($a, (array) $b);
}, []);

// Result: [1, 2, 3, 4]
artnikpro
источник
5

Это решение не является рекурсивным. Обратите внимание, что порядок элементов будет несколько смешанным.

function flatten($array) {
    $return = array();
    while(count($array)) {
        $value = array_shift($array);
        if(is_array($value))
            foreach($value as $sub)
                $array[] = $sub;
        else
            $return[] = $value;
    }
    return $return;
}
слишком много PHP
источник
1
Умная идея, но есть ошибка. «$ array [] = $ value» не добавляет все элементы $ value в $ array, оно просто добавляет само $ value. Если вы запустите этот код, он будет зацикливаться бесконечно.
Тодд Оуэн
Да, shiftingзначение из массива и добавление его в конец не имеет особого смысла. Я думаю, что вы хотели array_merge()вместо этого?
deceze
4

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

<?php

function flatten($array)
{
    return array_reduce($array, function($acc, $item){
        return array_merge($acc, is_array($item) ? flatten($item) : [$item]);
    }, []);
}


// usage
$array = [1, 2, [3, 4], [5, [6, 7]], 8, 9, 10];
print_r(flatten($array));
Дариуш Алипур
источник
3

Попробуйте следующую простую функцию:

function _flatten_array($arr) {
  while ($arr) {
    list($key, $value) = each($arr); 
    is_array($value) ? $arr = $value : $out[$key] = $value;
    unset($arr[$key]);
  }
  return (array)$out;
}

Итак, из этого:

array (
  'und' => 
  array (
    'profiles' => 
    array (
      0 => 
      array (
        'commerce_customer_address' => 
        array (
          'und' => 
          array (
            0 => 
            array (
              'first_name' => 'First name',
              'last_name' => 'Last name',
              'thoroughfare' => 'Address 1',
              'premise' => 'Address 2',
              'locality' => 'Town/City',
              'administrative_area' => 'County',
              'postal_code' => 'Postcode',
            ),
          ),
        ),
      ),
    ),
  ),
)

ты получаешь:

array (
  'first_name' => 'First name',
  'last_name' => 'Last name',
  'thoroughfare' => 'Address 1',
  'premise' => 'Address 2',
  'locality' => 'Town/City',
  'administrative_area' => 'County',
  'postal_code' => 'Postcode',
)
kenorb
источник
Может быть, вы должны проверить свою функцию ... кажется, не работа, как ожидалось
Эмилиано
@ Emiliano Попробуйте задать новый вопрос, может быть, ваши входные данные отличаются, поэтому он не будет работать в вашем конкретном случае.
Кенорб
у нас есть несколько проблем, каждая из которых является устаревшей функцией, вы можете улучшить этот момент, если вы не новичок здесь, вы должны знать об этом вторым, если ваш код работает с определенной версией php, скажи третье, если не работает со всеми данными, скажем
Эмилиано
2

Хитрость заключается в передаче массива источника и назначения по ссылке.

function flatten_array(&$arr, &$dst) {
    if(!isset($dst) || !is_array($dst)) {
        $dst = array();
    }
    if(!is_array($arr)) {
        $dst[] = $arr;
    } else {
        foreach($arr as &$subject) {
            flatten_array($subject, $dst);
        }
    }
}

$recursive = array('1', array('2','3',array('4',array('5','6')),'7',array(array(array('8'),'9'),'10')));
echo "Recursive: \r\n";
print_r($recursive);
$flat = null;
flatten_array($recursive, $flat);

echo "Flat: \r\n";
print_r($flat);

// If you change line 3 to $dst[] = &$arr; , you won't waste memory,
// since all you're doing is copying references, and imploding the array 
// into a string will be both memory efficient and fast:)

echo "String:\r\n";
echo implode(',',$flat);
Рик Гарсия
источник
2
/**
 * For merging values of a multidimensional array into one 
 *
 * $array = [
 *     0 => [
 *         0 => 'a1',
 *         1 => 'b1',
 *         2 => 'c1',
 *         3 => 'd1'
 *     ],
 *     1 => [
 *         0 => 'a2',
 *         1 => 'b2',
 *         2 => 'c2',
 *     ]
 * ];
 *
 * becomes : 
 *
 * $array = [
 *     0 => 'a1',
 *     1 => 'b1',
 *     2 => 'c1',
 *     3 => 'd1',
 *     4 => 'a2',
 *     5 => 'b2',
 *     6 => 'c2',
 *     
 * ]
 */
array_reduce
(
    $multiArray
    , function ($lastItem, $currentItem) {
        $lastItem = $lastItem ?: array();
        return array_merge($lastItem, array_values($currentItem));
    }
);

Фрагмент Gist

Arsham
источник
Кажется, это поддерживает только двумерные массивы.
Аликс Аксель
Ты прав. Нет смысла его использовать. Я думаю, что лучшим решением является ответ "слишком много PHP".
Аршам
2

Если вам действительно не нравится рекурсия ... попробуйте вместо этого переключиться :)

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$o = [];
for ($i=0; $i<count($a); $i++) {
    if (is_array($a[$i])) {
        array_splice($a, $i+1, 0, $a[$i]);
    } else {
        $o[] = $a[$i];
    }
}

Примечание: в этой простой версии это не поддерживает ключи массива.

BurninLeo
источник
это интересный подход. в отличие от других решений, он редактирует исходный массив ($ a). Если вы замените его на continue, это несколько быстрее.
pcarvalho
2

Как насчет использования рекурсивного генератора? https://ideone.com/d0TXCg

<?php

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

foreach (iterate($array) as $item) {
    var_dump($item);
};

function iterate($array)
{
    foreach ($array as $item) {
        if (is_array($item)) {
            yield from iterate($item);
        } else {
            yield $item;
        }
    }
}
Андрей
источник
1

Для PHP 5.2

function flatten(array $array) {
    $result = array();

    if (is_array($array)) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                $result = array_merge($result, flatten($v));
            } else {
                $result[] = $v;
            }
        }
    }

    return $result;
}
Алексей Т
источник
Пожалуйста, включите некоторые объяснения в этот ответ только для кода.
mickmackusa
1

Эта версия может делать глубокие, мелкие или определенное количество уровней:

/**
 * @param  array|object $array  array of mixed values to flatten
 * @param  int|boolean  $level  0:deep, 1:shallow, 2:2 levels, 3...
 * @return array
 */
function flatten($array, $level = 0) {
    $level = (int) $level;
    $result = array();
    foreach ($array as $i => $v) {
        if (0 <= $level && is_array($v)) {
            $v = flatten($v, $level > 1 ? $level - 1 : 0 - $level);
            $result = array_merge($result, $v);
        } elseif (is_int($i)) {
            $result[] = $v;
        } else {
            $result[$i] = $v; 
        }
    }
    return $result;
}
ryanve
источник
Помимо объяснения того, что может делать этот фрагмент , пожалуйста, объясните будущим исследователям, как он работает.
mickmackusa
1

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

/**
 * Flattens a multi demensional array into a one dimensional
 * to be compatible with hidden html fields.
 *
 * @param array $array
 *  Array in the form:
 *  array(
 *    'a' => array(
 *      'b' => '1'
 *    )
 *  )
 *
 * @return array
 *  Array in the form:
 *  array(
 *    'a[b]' => 1,
 *  )
 */
function flatten_array($array) {
  // Continue until $array is a one-dimensional array.
  $continue = TRUE;
  while ($continue) {
    $continue = FALSE;

    // Walk through top and second level of $array and move 
    // all values in the second level up one level.
    foreach ($array as $key => $value) {
      if (is_array($value)) {
        // Second level found, therefore continue.
        $continue = TRUE;

        // Move each value a level up.
        foreach ($value as $child_key => $child_value) {
          $array[$key . '[' . $child_key . ']'] = $child_value;
        }

        // Remove second level array from top level.
        unset($array[$key]);
      }
    }
  }

  return $array;
}
Gellweiler
источник
1

Это может быть достигнуто с помощью array_walk_recursive

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
array_walk_recursive($a, function($v) use (&$r){$r[]=$v;});
print_r($r);

Рабочий пример: - https://3v4l.org/FpIrG

Ракеш Джахар
источник
0

Это мое решение, используя ссылку:

function arrayFlatten($array_in, &$array_out){

    if(is_array($array_in)){
        foreach ($array_in as $element){
               arrayFlatten($element, $array_out);
        }
    }
    else{
        $array_out[] = $array_in; 
    }
}

$arr1 = array('1', '2', array(array(array('3'), '4', '5')), array(array('6')));

arrayFlatten($arr1, $arr2);

echo "<pre>";
print_r($arr2);
echo "</pre>";
Мартын Шотт
источник
Пожалуйста, включите некоторые объяснения того, как работает ваш фрагмент кода и почему это хорошая идея. Ответы только на код не имеют большого значения в StackOverflow, потому что они плохо справляются с обучением / расширением возможностей OP и будущих исследователей. Помните, мы никогда не говорим ТОЛЬКО с ФП; старые страницы используются для закрытия новых страниц, поэтому страницы должны быть достаточно информативными, чтобы решать вопросы и для будущих участников.
mickmackusa
0
<?php
//recursive solution

//test array
$nested_array = [[1,2,[3]],4,[5],[[[6,[7=>[7,8,9,10]]]]]];

/*-----------------------------------------
function call and return result to an array
------------------------------------------*/
$index_count = 1;
$flatered_array = array();
$flatered_array = flat_array($nested_array, $index_count);

/*-----------------------------------------
Print Result
-----------------------------------------*/
echo "<pre>";
print_r($flatered_array);


/*-----------------------------------------
function to flaten an array 
-----------------------------------------*/
function flat_array($nested_array, & $index_count, & $flatered_array) {

  foreach($nested_array AS $key=>$val) {
      if(is_array($val)) {
        flat_array($val, $index_count, $flatered_array);
      }
      else {
        $flatered_array[$index_count] = $val;
        ++$index_count;
      }      
  }

return $flatered_array;
}
?>
Фуркан Фрид
источник
0

Вот упрощенный подход:

$My_Array = array(1,2,array(3,4, array(5,6,7), 8), 9);

function checkArray($value) {
    foreach ($value as $var) {
        if ( is_array($var) ) {
            checkArray($var);
        } else {
            echo $var;
        }
    }
}

checkArray($My_Array);
разъем
источник
0

Любой, кто ищет действительно чистое решение для этого; вот вариант:

$test_array = array(
    array('test' => 0, 0, 0, 0),
    array(0, 0, 'merp' => array('herp' => 'derp'), 0),
    array(0, 0, 0, 0),
    array(0, 0, 0, 0)
);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($test_array));
var_dump( iterator_to_array($it, false) ) ; 

Печать

 0 0 0 0 0 0 derp 0 0 0 0 0 0 0 0 0
Льюис
источник
0

Просто выкладываю еще какое-то решение)

function flatMultidimensionalArray(array &$_arr): array
{
    $result = [];
    \array_walk_recursive($_arr, static function (&$value, &$key) use (&$result) {
        $result[$key] = $value;
    });

    return $result;
}
Джеймс Бонд
источник
0

Если вы хотите сохранить ваши ключи, это решение.

function reduce(array $array) {
    $return = array();
    array_walk_recursive($array, function($value, $key) use (&$return) { $return[$key] = $value; });
    return $return;
}

К сожалению, он выводит только окончательные вложенные массивы без средних клавиш. Итак, для следующего примера:

$array = array(
    'sweet' => array(
        'a' => 'apple',
        'b' => 'banana'),
    'sour' => 'lemon'); 
print_r(flatten($fruits));

Выход:

Array
(
    [a] => apple
    [b] => banana
    [sour] => lemon
)
Tajni
источник
-1

Мне нужно было представить многомерный массив PHP в формате ввода HTML.

$test = [
    'a' => [
        'b' => [
            'c' => ['a', 'b']
        ]
    ],
    'b' => 'c',
    'c' => [
        'd' => 'e'
    ]
];

$flatten = function ($input, $parent = []) use (&$flatten) {
    $return = [];

    foreach ($input as $k => $v) {
        if (is_array($v)) {
            $return = array_merge($return, $flatten($v, array_merge($parent, [$k])));
        } else {
            if ($parent) {
                $key = implode('][', $parent) . '][' . $k . ']';

                if (substr_count($key, ']') != substr_count($key, '[')) {
                    $key = preg_replace('/\]/', '', $key, 1);
                }
            } else {
                $key = $k;
            }           

            $return[$key] = $v;
        }
    }

    return $return;
};

die(var_dump( $flatten($test) ));

array(4) {
  ["a[b][c][0]"]=>
  string(1) "a"
  ["a[b][c][1]"]=>
  string(1) "b"
  ["b"]=>
  string(1) "c"
  ["c[d]"]=>
  string(1) "e"
}
Gajus
источник
@AlixAxel Как этот комментарий относительно? Неправильный пост ..?
Гайус
Нет. Я подумал, что это очень похоже на то, что вы делаете, и решил поделиться им, я думаю, единственное отличие состоит в том, что мое представление также является действительным PHP - формы $var['a']['b']['c'][0] = 'a'; ....
Аликс Аксель
Я намеренно нуждался в выводе HTML. Хоть спасибо, что поделились.
Gajus
1
Я чувствую, что это правильный ответ на неправильный вопрос. При ответе, пожалуйста, попытайтесь ответить на вопрос так, как он задан - в противном случае страницы могут отойти от основной проблемы и привести в замешательство будущих исследователей.
mickmackusa
-1

Если у вас есть массив объектов и вы хотите сгладить его с помощью узла, просто используйте эту функцию:

function objectArray_flatten($array,$childField) {
    $result = array();
    foreach ($array as $node)
    {
        $result[] = $node;
        if(isset($node->$childField))
        {
            $result = array_merge(
                $result, 
                objectArray_flatten($node->$childField,$childField)
            );
            unset($node->$childField);
        }

    }
    return $result;
}
حسین شکرزاده
источник