PHP Laravel 5.5 collections flatten and keep the integer keys?
Asked Answered
P

3

13

I have the following array :

$array = [
    '2' => ['3' => ['56' => '2'], '6' => ['48' => '2']],
    '4' => ['4' => ['433' => '2', '140' => '2'], '8' => ['421' => '2', '140' => '2']],
    '5' => ['5' => ['88' => '4', '87' => '2']]
];

The following code (flattening) should return it by preserving keys, but it doesnt?

collect($array)->flatten(1);

should give me

[
    '3' => ['56' => '2'],
    '6' => ['48' => '2'],
    '4' => ['433' => '2', '140' => '2'],
    '8' => ['421' => '2', '140' => '2'],
    '5' => ['88' => '4', '87' => '2']
]

However it loses the keys, and just gives array results :/ Am I using it wrong? How should I flatten and preserve keys?

Philips answered 11/12, 2017 at 16:21 Comment(2)
I don't believe flatten supports maintaining keys - how would you expect it to work if the keys in a lower level weren't unique?Elbertina
OK, thanks. It makes sense in retrospect why flatten wouldn't keep the keys.Philips
R
55

An elegant solution is to use the mapWithKeys method. This will flatten your array and keep the keys:

collect($array)->mapWithKeys(function($a) {
    return $a;
});

The mapWithKeys method iterates through the collection and passes each value to the given callback. The callback should return an associative array containing a single key / value pair

Retrace answered 5/4, 2018 at 6:2 Comment(3)
It can be more elegant/shorter now with arrow function. Works only with PHP 7.4 and above collect($array)->mapWithKeys(fn($a) => $a);Quilmes
Very nice, thanks. Since map doesn't flatten, it's unintuitive that map with keys would.Petrie
same can be achieved with collect($array)->flatMap(fn ($v) => $v) which has the added bonus of having the word flat for a more expressive statement, although the fn ($v) => $v part ruins it.Porous
C
2

You can't use flatten() here. I don't have an elegant solution, but I've tested this and it works perfectly for your array:

foreach ($array as $items) {
    foreach ($items as $key => $item) {
        $newArray[$key] = $item;
    }
}

dd($newArray);
Counterproductive answered 11/12, 2017 at 16:44 Comment(1)
This did work. Trying to avoid foreach'es, but it did. thanks.Philips
D
0

mapWithKeys() is most direct if you wish to return a collection of all second level data as the new first level.

If you wish to return an array, you can call reduce() and use the array union operator in the callback. Otherwise, call toArray() after mapWithKeys() to produce an array.

Codes: (Demo)

var_export(
    collect($array)->reduce(fn($result, $set) => $result + $set, [])
);

Is the same as:

var_export(
    collect($array)->mapWithKeys(fn($set) => $set)->toArray()
);
Driftwood answered 16/4 at 21:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.