Як згладити багатовимірний масив?


259

Чи можливо в PHP згладити (бі / багато) розмірний масив без використання рекурсії чи посилань?

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


17
Чому слід уникати рекурсії?
JorenB

5
Dupe ( в основному) stackoverflow.com/questions/526556 / ...
Клетус

4
Ви не можете нічого зробити з усіма елементами довільно глибоких масивів без рекурсії (ви можете замаскувати це як ітерацію, але картоплю, потато.) Якщо ви просто хочете уникати запису коду обробки рекурсії самостійно, використовуйте dk2.php.net/ manual / en / function.array-walk-recursive.php із зворотним викликом, який додає елемент до наявного масиву (використовуйте глобальний параметр 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 

351
Я єдиний, хто думає, що "RecursiveIteratorIterator" - дурне ім'я?
nilamo

45
Це скоріше "логічно", ніж "прискіпливо". Не все може мати таке фантастичне ім’я, як JOGL, Knol або Azure :-)
VolkerK

7
Це не спрацює для порожніх масивів як дітей. Вони будуть повернуті як батьки.
хакре

45
iterator_to_array($it, false)уникає потреби в передбаченні.
Алікс Аксель

3
Спираючись на те, що презентували інші, я зміг створити цього маленького помічника: function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }Сподіваюся, це допомагає іншим.
Майк С.

295

Станом на PHP 5.3, здається, найкоротше рішенняarray_walk_recursive() новий синтаксис закриття:

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

33
якщо вам потрібні клавіші, функціонуйте вирівнювання (масив $ масив) {$ return = array (); array_walk_recursive ($ масив, функція ($ a, $ b) використання (& $ return) {$ return [$ b] = $ a;}); повернути $ повернення; }
Брендон-Ван-Хейзен

чи можете ви переписати це для використання з php 5.2?
Олексій

2
@Alex, на жаль, вам потрібен useсинтаксис, щоб зробити цю роботу, array_walk_recursiveоскільки він не прийме необов'язковий $userdataпараметр за посиланням
Tim Seguine

1
Схоже, добре працює для таких масивів -> ideone.com/DsmApP Але не для таких -> ideone.com/5Kltva Або це я?
Себастьян Піскорський

2
@Sebastian Piskorski - це тому, що до ваших значень поводяться як з ключами, тому щойно ви вводите в масив власну пару = = значення значень, ваші значення масиву в першій позиції індексу трактуються як ключі без значень, а тому, що ключі мають щоб бути унікальним, де дві клавіші відповідають, ваші значення додаються до одного ключа. Простим рішенням буде спочатку сортувати масив. Це поведінка, властива PHP.
Martyn Shutt

92

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

Спробуйте:

$array  = your array

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

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

EDIT: 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', [])(помічайте порожній масив) повертає null та запускає помилку попередження php. Це чітке рішення, якщо ви фактично знаєте, що ваш масив не буде порожнім, але це не є загальним припущенням, яке багато хто може зробити.
коза

ОП спеціально просила нерекурсивні рішення.
Електра

Ого, крутий 2д плоский! Але для запобігання сповіщення просто використовуйте$result = $array ?call_user_func_array('array_merge', $array) : [];
Олександр Гончаров

крутий бре, але хіба у вас випадково не зустрічається функція array-deflatten?
FantomX1

64

У 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якого я думаю, що це приємна ідея.


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

Тепер дуже залежить від вас, як ви будете працювати з ключами. Ура


EDIT (2017-03-01)

Цитуючи занепокоєння / проблему Найджела Альдертона :

Для уточнення це зберігає ключі (навіть цифрові), тому значення, які мають однаковий ключ, втрачаються. Наприклад $array = ['a',['b','c']]стає Array ([0] => b, [1] => c ). Це 'a'втрачено, тому що 'b'також має ключ0

Цитуючи відповідь Свіша :

Просто додайте 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.
Свиш

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>

1
Я не боюся рекурсії, просто хочу дізнатися інші способи зробити те саме.
Алікс Аксель

13
+1 для цієї рекурсії: Сподіваємось, побачивши, наскільки це не складний, ваш страх перед рекурсією розвіяється, як тільки ви побачите, наскільки це не складний.
Tiberiu-Ionuț Stan

1
Гаразд, це над мною. Як можливо, відповідь ("Я не боюся рекурсії") на три з половиною року старша (24 серпня 099 р.), Ніж початкова заява ("(...) ваш страх рекурсії розсіюється (... ) "), зроблений 5 лютого 1313?
trejder

18

Просто подумав, що я зазначив, що це складка, тому array_reduce можна використовувати:

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

EDIT: Зауважте, що це може складатися для вирівнювання будь-якої кількості рівнів. Це можна зробити кількома способами:

// 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.


Багатовимірність! = Двовимірний.
Алікс Аксель

@atamur Це працює на PHP 5.3+. Як зазначається в журналі змін для array_reduce, $ Initial може бути лише цілим числом до 5.3, тоді його можна було змішати (тобто все, що підтримує ваша функція зменшення)
Warbo

1
@AlixAxel Ви праві, що багатовимірний! = Двовимірний, але це може бути складено для вирівнювання будь-якої кількості рівнів. Одним із приємних наслідків складання складок є те, що вона дотримується фіксованої межі; якщо у мене масив вкладений до 5 рівнів, я можу foldйого на 4 рівні, або fold . foldна 3 рівні, або fold . fold . foldна 2 рівні тощо. Це також запобігає прихованню помилок; напр. якщо я хочу вирівняти 5D масив, але мені дано 4D масив, помилка запуститься негайно.
Варбо

Я люблю це рішення, для двовимірних масивів. Ідеально підходить до рахунку.
Том Ожер

Я погоджуюся, що ваше єдине визначення рівня є найкращою відповіддю, воно також чудово акуратне. Однак я думаю, що ви його неправильно назвали $concat, я думаю, вам слід просто назвати це $flatten. array_mergeє еквівалентом конфату php. Я намагався отримати 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]

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;
}

1
Розумна ідея, але є помилка. "$ array [] = $ value" не додає всіх елементів $ value до $ array, а лише додає $ value. Якщо запустити цей код, він буде циклічно нескінченно.
Тодд Оуен

Так, shiftingзначення масиву та додавання його до кінця не має особливого сенсу. Я думаю, що ти цього хотів array_merge()?
деге

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',
)

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

@Emiliano Спробуйте задати нове запитання, можливо, ваші вхідні дані відрізняються, тому це не спрацює у вашому конкретному випадку.
kenorb

у нас є кілька питань, кожна з них є застарілою функцією, ви можете вдосконалити цю точку, щоб ви не були новим хлопцем тут, ви повинні знати це друге, якщо ваш код працює з певною версією 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));
    }
);

Гіст-фрагмент


Здається, це підтримує лише двовимірні масиви.
Алікс Аксель

Ти правий. Немає сенсу його використовувати. Я думаю, що найкращим рішенням є відповідь "занадто багато 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];
    }
}

Примітка. У цій простій версії це не підтримує клавіші масиву.


це цікавий підхід. на відміну від інших рішень, він редагує вихідний масив ($ a). Якщо ви заміните його на 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;
}

Окрім пояснення того, що може зробити цей фрагмент , поясніть майбутнім дослідникам, як він працює.
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;
}

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, оскільки вони погано працюють з навчанням / розширенням можливостей ОП та майбутніх дослідників. Пам'ятайте, ми ніколи ТОЛЬКО не виступаємо з ОП; старі сторінки використовуються для закриття нових сторінок, тому сторінки повинні бути досить інформативними, щоб вирішити питання і для майбутніх запитувачів.
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
)

-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"
}


@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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.