Jak spłaszczyć macierz wielowymiarową?

259

Czy w PHP można spłaszczyć tablicę wymiarową (bi / multi) bez użycia rekurencji lub referencji?

Interesują mnie tylko wartości, więc klucze można zignorować, myślę w wierszach array_map()i array_values().

Alix Axel
źródło
17
Dlaczego warto unikać rekurencji?
JorenB
5
Dupe (głównie) stackoverflow.com/questions/526556/…
cletus
4
Nie możesz nic zrobić ze wszystkimi elementami arbitralnie głębokich tablic bez rekurencji (możesz ukryć to jako iterację, ale ziemniak, potahto.) Jeśli chcesz po prostu uniknąć pisania kodu obsługi rekurencji sam, użyj dk2.php.net/ manual / pl / function.array-walk-recursive.php z wywołaniem zwrotnym, które dodaje element do dostępnej tablicy (użyj globalnego, parametru userdata, umieść to wszystko w klasie i odwołaj się do $ this itp.)
Michael Madsen
@JorenB: Chciałbym, aby implementacja mogła zostać zarchiwizowana.
Alix Axel
Zobacz funkcję spłaszczania z Nspl . Możesz także określić za jego pomocą głębokość.
Ihor Burlachenko

Odpowiedzi:

276

Możesz użyć Standardowej Biblioteki PHP (SPL), aby „ukryć” rekursję.

$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, " ";
}

odciski

1 2 3 4 5 6 7 8 9 
VolkerK
źródło
351
Czy jestem jedyną osobą, która uważa „RecursiveIteratorIterator” to głupie imię?
nilamo
45
Jest to bardziej „logiczne” niż „chwytliwe”. Nie wszystko może mieć tak fantastyczną nazwę jak JOGL, Knol lub Azure :-)
VolkerK
7
To nie zadziała dla pustych tablic jako dzieci. Zostaną zwrócone jako rodzic.
hakre
45
iterator_to_array($it, false)unika potrzeby foreach.
Alix Axel,
3
Opierając się na tym, co przedstawili inni, udało mi się stworzyć tego małego pomocnika: function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }Mam nadzieję, że to pomaga innym.
Mike S.
295

W PHP 5.3 najkrótszym rozwiązaniem wydaje się być array_walk_recursive()nowa składnia zamknięć:

function flatten(array $array) {
    $return = array();
    array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
    return $return;
}
za dużo php
źródło
33
jeśli chcesz klucze, spłaszcz funkcję (tablica $ tablica) {$ return = array (); array_walk_recursive ($ tablica, funkcja ($ a, $ b) use (& $ return) {$ return [$ b] = $ a;}); return $ return; }
Brendon-Van-Heyzen
czy możesz przepisać to na php 5.2?
Alex
2
@Alex niestety potrzebujesz useskładni, aby działała, array_walk_recursiveponieważ nie akceptuje $userdataparametru opcjonalnego przez odniesienie
Tim Seguine
1
Wygląda na to, że działa dobrze dla takich tablic -> ideone.com/DsmApP Ale nie dla takich -> ideone.com/5Kltva Czy to ja?
Sebastian Piskorski,
2
@Sebastian Piskorski to dlatego, że twoje wartości są traktowane jak klucze, więc jak tylko wprowadzisz własną parę klucz => wartość w tablicy, twoje wartości tablicy w pierwszej pozycji indeksu są traktowane jak klucze bez wartości, a ponieważ klucze mają aby być wyjątkowym, gdy dwa klucze pasują do siebie, twoje wartości zostaną dodane do tego samego klucza. Prostym rozwiązaniem byłoby posortowanie tablicy w pierwszej kolejności. Jest to zachowanie nieodłącznie związane z PHP.
Martyn Shutt,
92

Rozwiązanie dla 2-wymiarowej tablicy

Spróbuj tego:

$array  = your array

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

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

EDYCJA: 21 sierpnia-13

Oto rozwiązanie, które działa dla macierzy wielowymiarowej:

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

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

Prasanth Bendra
źródło
Dziękuję, pierwszy z nich pracował na tablicy, którą otrzymywałem od PDO, gdzie inne rozwiązania nie.
JAL
7
To kiepska strategia. call_user_func_array('array_merge', [])(zwróć uwagę na pustą tablicę) zwraca null i wyzwala błąd ostrzegawczy php. Jest to łatwe rozwiązanie, jeśli wiesz na pewno, że tablica nie będzie pusta, ale nie jest to częste założenie, które wielu może poczynić.
koza
OP specjalnie poprosił o rozwiązania nierekurencyjne.
Élektra
Wow, fajne 2d flattern! Ale aby zapobiec powiadomieniu, po prostu użyj$result = $array ?call_user_func_array('array_merge', $array) : [];
Alexander Goncharov
fajnie, ale czy nie masz przypadkowo spłaszczonej tablicy przeciwnej funkcji?
FantomX1
64

W PHP 5.6 i nowszych możesz spłaszczyć tablice dwuwymiarowe array_mergepo rozpakowaniu tablicy zewnętrznej za pomocą ...operatora. Kod jest prosty i przejrzysty.

array_merge(...$a);

Działa to również z kolekcją tablic asocjacyjnych.

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

Ale to nie działa, gdy zewnętrzna tablica ma klucze nienumeryczne. W takim przypadku najpierw musisz zadzwonić 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
)

Aktualizacja: Na podstawie komentarza @MohamedGharib

To wyrzuci błąd, jeśli tablica zewnętrzna jest pusta, ponieważ array_mergezostałaby wywołana z zerowymi argumentami. Można tego uniknąć, dodając pustą tablicę jako pierwszy argument.

array_merge([], ...$a);
Joyce Babu
źródło
1
Działa to TYLKO wtedy, gdy każdy element tablicy jest tablicą. Jeśli tablica zawiera typy mieszane, takie jak skalary, wystąpi błąd.
Otheus
@Otheus To dlatego, że powyższe rozwiązanie nie używa rekurencji. Jak powiedziałeś, wymaga tablicy. Ale na plus, powinno to być znacznie szybsze niż w przypadku innych metod, ponieważ nie ma dodatkowego obciążenia wywołania funkcji.
Joyce Babu
2
Zgłasza błąd, jeśli zewnętrzna tablica jest pusta, można tego uniknąć, jeśli zostanie połączona z pustą tablicąarray_merge([], ...$a);
Mohamed Gharib
@MohamedGharib Nice catch.
Joyce Babu
Jeśli używasz tablic asocjacyjnych, możesz sprawdzić to rozwiązanie stackoverflow.com/questions/40663687/…
alex
24

Aby spłaszczyć bez rekurencji (tak jak prosiłeś), możesz użyć stosu . Oczywiście możesz wprowadzić tę funkcję jako własną array_flatten. Oto wersja, która działa bez kluczy :.

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

Elementy przetwarzane są w kolejności. Ponieważ podelementy zostaną przeniesione na stos, zostaną one przetworzone w następnej kolejności.

Możliwe jest również uwzględnienie kluczy, jednak do obsługi stosu potrzebna będzie inna strategia. Jest to konieczne, ponieważ musisz poradzić sobie z możliwymi duplikatami kluczy w pod-tablicach. Podobna odpowiedź w pokrewnym pytaniu: PHP Przejdź przez wielowymiarową tablicę zachowując klucze

Nie jestem do końca pewien, ale II przetestowałem to w przeszłości: RecurisiveIteratorużywa rekurencji, więc zależy to od tego, czego naprawdę potrzebujesz. Powinno być również możliwe utworzenie iteratora rekurencyjnego na podstawie stosów:

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

Próbny

Do tej pory nie udało mi się wdrożyć stosu, na podstawie RecursiveIteratorktórego moim zdaniem jest to dobry pomysł.

hakre
źródło
+1 za wybitną funkcję array_flatten. Musiałem dodać if(!empty($value)){$flat[] = $value}wewnątrz instrukcji else, aby zapobiec dodaniu pustego do tablicy wyników. Niesamowita funkcja!
Alex Sarnowski
19

Prosta i jednokierunkowa odpowiedź.

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

Stosowanie:

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

print_r( flatten_array($array) );

Wyjście (w PsySH):

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

Teraz zależy od ciebie, jak poradzisz sobie z kluczami. Twoje zdrowie


EDYCJA (2017-03-01)

Cytując problem / problem Nigela Aldertona :

Aby to wyjaśnić, zachowuje klucze (nawet te numeryczne), więc wartości, które mają ten sam klucz, zostają utracone. Na przykład $array = ['a',['b','c']]staje się Array ([0] => b, [1] => c ). 'a'Jest stracone, ponieważ 'b'ma również klucz0

Cytując odpowiedź Svisha :

Po prostu dodaj false jako drugi parametr ($use_keys)do wywołania iterator_to_array

Allen Linatoc
źródło
Aby to wyjaśnić, zachowuje klucze (nawet te numeryczne), więc wartości, które mają ten sam klucz, zostają utracone. Na przykład $array = ['a',['b','c']]staje się Array ([0] => b, [1] => c ). 'a'Jest stracone, ponieważ 'b'ma również klucz 0.
Nigel Alderton,
1
@NigelAlderton Wystarczy dodać falsejako drugi parametr ( $use_keys) do iterator_to_arraywywołania.
Svish
18

Wykorzystuje rekurencję. Mam nadzieję, że po zobaczeniu, jak to nie jest skomplikowane, twój strach przed rekurencją rozproszy się, gdy zobaczysz, jak to nie jest skomplikowane.

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

Wynik:

<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
źródło
1
Nie boję się rekurencji, chcę tylko nauczyć się innych sposobów, aby zrobić to samo.
Alix Axel
13
+1 za tę rekurencję: Mam nadzieję, że po zobaczeniu, jak nie jest złożona, twój strach przed rekurencją rozproszy się, gdy zobaczysz, jak nie jest złożona.
Tiberiu-Ionuț Stan
1
OK, to już koniec. Jak to możliwe, że odpowiedź („Nie boję się rekurencji”) jest trzy i pół roku starsza (24 sierpnia 2009 r.) Niż wstępne oświadczenie („(...) strach przed rekurencją rozproszy się (... ) "), wykonane 5 lutego 2013 r.?
trejder
18

Pomyślałem, że zwrócę uwagę na to, że jest to fold, więc można użyć array_reduce:

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

EDYCJA: Zauważ, że można to skomponować w celu spłaszczenia dowolnej liczby poziomów. Możemy to zrobić na kilka sposobów:

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

Oczywiście, moglibyśmy również użyć pętli, ale pytanie wymaga funkcji kombinatorycznej wzdłuż linii array_map lub array_values.

Warbo
źródło
Wielowymiarowe! = Dwuwymiarowe.
Alix Axel
@atamur Działa na PHP 5.3+. Jak zauważono w dzienniku zmian dla array_reduce, $ initial może być tylko liczbą całkowitą przed 5.3, potem można było „mieszać” (tj. Wszystko, co obsługuje twoja funkcja redukcji)
Warbo
1
@AlixAxel Masz rację, że wielowymiarowy! = Dwuwymiarowy, ale można to skomponować, aby spłaszczyć dowolną liczbę poziomów. Jedną z miłych konsekwencji komponowania fałd jest to, że przestrzega ustalonego limitu; jeśli mam tablicę zagnieżdżoną na 5 poziomach, mogę foldją ustawić na 4 poziomy, albo fold . folduzyskać 3 poziomy, albo fold . fold . folduzyskać 2 poziomy itp. Zapobiega to również ukrywaniu się błędów; na przykład. jeśli chcę spłaszczyć tablicę 5D, ale dostaję tablicę 4D, błąd zostanie natychmiast wyzwolony.
Warbo,
Uwielbiam to rozwiązanie dla tablic dwuwymiarowych. Idealnie pasuje do rachunku.
Tom Auger,
Zgadzam się, że twoja definicja jednego poziomu jest najlepszą odpowiedzią, jest także cudownie schludna. Jakkolwiek myślę, że źle go nazwałeś $concat, myślę, że powinieneś to po prostu nazwać $flatten. array_mergejest php odpowiednikiem concat. Próbowałem zostać array_concatdodany jako alias dla array_merge.
icc97
9

Spłaszcza tylko tablice dwuwymiarowe:

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

// Result: [1, 2, 3, 4]
artnikpro
źródło
5

To rozwiązanie nie jest rekurencyjne. Zauważ, że kolejność elementów będzie nieco mieszana.

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;
}
za dużo php
źródło
1
Sprytny pomysł, ale jest błąd. „$ array [] = $ value” nie dodaje wszystkich elementów $ value do $ array, a jedynie sama dodaje $ value. Jeśli uruchomisz ten kod, zapętla się w nieskończoność.
Todd Owen
Tak, shiftingwartość poza tablicą i ponowne dołączenie jej na końcu nie ma większego sensu. Chyba array_merge()zamiast tego chciałeś ?
deceze
4

Uważam, że jest to najczystsze rozwiązanie bez użycia mutacji ani nieznanych klas.

<?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));
Dariush Alipour
źródło
3

Wypróbuj następującą prostą funkcję:

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

Więc z tego:

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

dostajesz:

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
źródło
może powinieneś sprawdzić swoją funkcję ... wydaje się, że nie ma pracy zgodnie z oczekiwaniami
Emiliano
@Emiliano Spróbuj zadać nowe pytanie, być może twoje dane wejściowe są inne, więc nie będzie działać w twoim przypadku.
kenorb,
mamy kilka problemów, każdy z nich jest przestarzałą funkcją, możesz poprawić to, że nie byłeś tu nowym facetem, powinieneś wiedzieć to na drugim miejscu, jeśli twój kod działa z określoną wersją php, powiedz, że jest trzeci, jeśli nie działa ze wszystkimi danymi, powiedz to
Emiliano,
2

Sztuczka polega na przekazywaniu tablic źródłowej i docelowej przez odniesienie.

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);
Rick Garcia
źródło
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));
    }
);

Fragment kodu

Arszam
źródło
Wydaje się, że obsługuje to tylko tablice dwuwymiarowe.
Alix Axel
Masz rację. Nie ma sensu z niego korzystać. Myślę, że najlepszym rozwiązaniem jest odpowiedź „za dużo php”.
Arsham,
2

Jeśli naprawdę nie lubisz rekurencji ... spróbuj zamiast tego zmienić :)

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

Uwaga: W tej prostej wersji nie obsługuje kluczy tablicy.

BurninLeo
źródło
to ciekawe podejście. w przeciwieństwie do innych rozwiązań, edytuje oryginalną tablicę ($ a). Jeśli zastąpisz go na continue, będzie nieco szybszy.
pcarvalho
2

Co powiesz na użycie generatora rekurencyjnego? 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;
        }
    }
}
Andrij
źródło
1

Dla 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;
}
Alexei T.
źródło
Podaj wyjaśnienie do tej odpowiedzi tylko do kodu.
mickmackusa,
1

Ta wersja może wykonywać głębokie, płytkie lub określoną liczbę poziomów:

/**
 * @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
źródło
Oprócz wyjaśnienia, co może zrobić ten fragment , wyjaśnij przyszłym badaczom, jak on działa.
mickmackusa,
1

Ponieważ kod tutaj wygląda przerażająco. Oto funkcja, która przekształci również tablicę wielowymiarową w składnię zgodną z formą HTML, ale jest łatwiejsza do odczytania.

/**
 * 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
źródło
1

Można to osiągnąć za pomocą 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);

Przykład roboczy: - https://3v4l.org/FpIrG

Rakesh Jakhar
źródło
0

Oto moje rozwiązanie, korzystając z referencji:

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>";
Martyn Shutt
źródło
Dołącz wyjaśnienie, w jaki sposób działa Twój fragment kodu i dlaczego jest to dobry pomysł. Odpowiedzi zawierające tylko kod mają niską wartość w StackOverflow, ponieważ źle radzą sobie z edukowaniem / wzmacnianiem PO i przyszłych badaczy. Pamiętaj, że nigdy nie rozmawiamy WYŁĄCZNIE z OP; stare strony służą do zamykania nowych stron, więc strony muszą być wystarczająco informacyjne, aby rozwiązać problemy również dla przyszłych pytających.
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;
}
?>
Furqan Freed
źródło
0

Oto uproszczone podejście:

$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);
Jacek
źródło
0

Każdy, kto szuka naprawdę czystego rozwiązania tego problemu; oto opcja:

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

Wydruki

 0 0 0 0 0 0 derp 0 0 0 0 0 0 0 0 0
Chwytak
źródło
0

Wystarczy opublikować jakieś inne rozwiązanie)

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

    return $result;
}
James Bond
źródło
0

Jeśli chcesz zachować swoje klucze, to jest rozwiązanie.

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

Niestety generuje tylko końcowe zagnieżdżone tablice, bez środkowych klawiszy. W poniższym przykładzie:

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

Dane wyjściowe to:

Array
(
    [a] => apple
    [b] => banana
    [sour] => lemon
)
Tajni
źródło
-1

Musiałem reprezentować wielowymiarową tablicę PHP w formacie wejściowym 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
źródło
@AlixAxel Jak względny jest ten komentarz? Niewłaściwy post ..?
Gajus
Nie. Myślałem, że to bardzo podobne do tego, co robisz i postanowiłem się tym podzielić. Myślę, że jedyną różnicą jest to, że moja reprezentacja jest również poprawna w PHP - w formie $var['a']['b']['c'][0] = 'a'; ....
Alix Axel
Celowo potrzebowałem danych wyjściowych HTML. Chociaż dziękuję za udostępnienie.
Gajus
1
Uważam, że to właściwa odpowiedź na złe pytanie. Odpowiadając, spróbuj odpowiedzieć na zadane pytanie - w przeciwnym razie strony mogą odejść od podstawowego problemu i pozostawić przyszłym badaczom zdezorientowany.
mickmackusa,
-1

Jeśli masz tablicę obiektów i chcesz spłaszczyć ją za pomocą węzła, po prostu użyj tej funkcji:

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;
}
حسین شکرزاده
źródło