An Array of Challenges #2: Separate a Nested Array Note: This is #2 in a series of array-manipulation challenges. For the previous challenge, click here.

Separating Nested Lists


  To separate values in a nested list, flatten it, and then wrap each value so it is at the same nested depth as before. 


That is to say, this list:

[1, [2, 3], [4, 4, [5, 2], 1]]


Would become:

[1, [2], [3], [4], [4], [[5]], [[2]], [1]]




The Challenge

Your task is to write a program which takes any nested list of positive integers (within your language's limits) and performs this separation operation. 

You may submit a function which takes the list as an argument, or a full program which performs I/O.

As this is code-golf, the shortest submission (in bytes) wins!*

*Standard golfing loopholes are banned. You know the drill.



Test Cases

Input lists will only ever contain integers in your language's standard integer size. To avoid languages' constraints preventing them from competing, values will not be nested at depths of more than 10.

You may assume that input will not have empty sub-lists: for example - [[5, []]] will not be given. However, the main list could be empty.

[]            -&gt;  []

[[1, 2]]      -&gt;  [[1], [2]]
[3, [4, 5]]   -&gt;  [3, [4], [5]]
[3, [3, [3]]] -&gt;  [3, [3], [[3]]]
[[6, [[7]]]]  -&gt;  [[6], [[[7]]]]
[[5, 10], 11] -&gt;  [[5], [10], 11]


Don't hesitate to leave a comment if I've missed out a corner case.

Example

I threw together a quick (ungolfed) Python 3 solution as an example - you can test it on repl.it.
Mathematica, 24 21 bytes

##&amp;@@List/@#0/@#&amp;/@#&amp;


or one of these:

##&amp;@@List/@#&amp;/@#0/@#&amp;
##&amp;@@List@*#0/@#&amp;/@#&amp;
##&amp;@@List/@#&amp;@*#0/@#&amp;


Explanation

The reason this is so short is that it's basically a recursion that doesn't require an explicit base case.

There's a lot of syntactic sugar here, so let's start by ungolfing this. &amp; denotes an unnamed function left of it, whose argument is written as #. Inside this function #0 refers to the function itself, which allows one to write unnamed recursive functions. But let's start by giving the inner function a name and pulling it out:

f[x_] := ##&amp; @@ List /@ f /@ x
f /@ # &amp;


The other important syntactic sugar is f/@x which is short for Map[f, x] i.e. it calls f on every element of x. The reason f[x_] := ... f /@ x doesn't lead to infinite recursion is that mapping something over an atom leaves the atom unchanged without actually calling the function. Hence, we don't need to check for the base case (current element is an integer) explicitly.

So the function f first recurses down to the deepest list inside x, at which point f/@ becomes a no-op. Then we call use ##&amp; @@ List /@ on that. Mapping List over the list simply wraps each element in a separate list, so {1, 2, 3} becomes {{1}, {2}, {3}}. Then we apply ##&amp; to it, which means the head (i.e. the outer list) gets replaced by ##&amp;, so this turns into ##&amp;[{1}, {2}, {3}]. But ##&amp; simply returns it's arguments as a Sequence (which you can think of as an unwrapped list, or a sort of "splat" operator in other languages).

So ##&amp; @@ List /@ turns a list {1, 2, 3} into {1}, {2}, {3} (kind of, that last thing is actually wrapped in the head Sequence, but that vanishes as soon as we use the value anywhere).

That leaves the question why f itself isn't already the solution to the challenge. The problem is that the outermost list should be treated differently. If we have input {{1, 2}, {3, 4}} we want {{1}, {2}, {3}, {4}} and not {{1}}, {{2}}, {{3}}, {{4}}. My original solution fixed this by passing the final result as a list of arguments to Join which would restore the outer level of lists, but this one just skips the outer level by using f itself in a map on the output. Hence f is only applied to the individual elements of the outermost list and never gets to touch that list.

As for the other three solutions, the first one simply applies the recursion outside of f which works just as well. The other two solutions avoid a repeated Map operation by first composing two functions and then mapping the result only once.