337 Stimmen

Wie kann man ein mehrdimensionales Array reduzieren?

Ist es möglich, in PHP ein (bi-/multi) dimensionales Array ohne Rekursion oder Referenzen zu reduzieren?

Ich interessiere mich nur für die Werte, so dass die Schlüssel ignoriert werden können, ich denke in den Linien der array_map() y array_values() .

24voto

Warbo Punkte 2482

Nur dachte, ich würde darauf hinweisen, dass dies eine Falte ist, so array_reduce verwendet werden kann:

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

EDIT: Beachten Sie, dass dies zusammengesetzt werden kann, um eine beliebige Anzahl von Ebenen zu glätten. Wir können dies auf verschiedene Arten tun:

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

Natürlich könnten wir auch Schleifen verwenden, aber die Frage fragt nach einer Kombinatorfunktion nach dem Vorbild von array_map oder array_values.

23voto

Allen Linatoc Punkte 584

Unkompliziert y Einzeiler Antwort.

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

Verwendung:

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

print_r( flatten_array($array) );

Ausgabe (in PsySH):

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

Jetzt liegt es ganz bei Ihnen, wie Sie mit den Schlüsseln umgehen. Prost


EDIT (2017-03-01)

Zitat Nigel Alderton Anliegens/Problems:

Nur zur Klarstellung: Schlüssel (auch numerische) werden beibehalten, so dass Werte, die denselben Schlüssel haben, verloren gehen. Zum Beispiel $array = ['a',['b','c']] wird Array ([0] => b, [1] => c ) . Die 'a' verloren ist, weil 'b' hat auch einen Schlüssel von 0

Zitat Svish die Antwort:

Fügen Sie einfach false als zweiten Parameter hinzu ($use_keys) zum Iterator_zu_Array aufrufen

18voto

nilamo Punkte 1904

Verwendet Rekursion. Hoffentlich wird Ihre Angst vor Rekursion verschwinden, sobald Sie sehen, wie wenig komplex sie ist.

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

Ausgabe:

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

12voto

artnikpro Punkte 4957

Glättet nur zweidimensionale Arrays:

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

// Result: [1, 2, 3, 4]

7voto

too much php Punkte 85034

Diese Lösung ist nicht rekursiv. Beachten Sie, dass die Reihenfolge der Elemente etwas gemischt sein wird.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X