Simplificate an array
Perl, 52 bytes
Just a recursive subroutine. (unusual for a Perl answer, I know..)
sub f{say"@{[grep!ref,@_]}";@_&&f(map/A/?@$_:(),@_)}
Call it like that :
$ perl -E 'sub f{say"@{[grep!ref,@_]}";@_&&f(map/A/?@$_:(),@_)}f(1, [2, 3], [[4]], [[[5, 6], 7, [[[8]]]], 9])'
1
2 3 9
4 7
5 6
8
Each line of the output corresponds to a depth level of the array (hence the empty line in the example above).
It can be turned into a full program for just a few more bytes : add -n
flag and an eval
(inside @{ }
to transform the input into an array and not an arrayref) to transform the input into a Perl array :
perl -nE 'sub f{say"@{[grep!ref,@_]}";@_&&f(map/A/?@$_:(),@_)}f(@{+eval})' <<< "[1, [2, 3], [[4]], [[[5, 6], 7, [[[8]]]], 9]]"
My previous approach was slightly longer (65 bytes), but still interesting, so I'll let it here :
perl -nE '/\d/?push@{$;[$d-1]},$_:/]/?$d--:$d++for/\[|]|\d+/g;say"@$_"for@' <<< "[1, [2, 3], [[4]], [[[5, 6], 7, [[[8]]]], 9]]"
JavaScript (ES6), 139 109 bytes
f=(a,v=b=>a.filter(a=>b^!a[0]))=>a[0]?v().concat((a=f([].concat(...v(1))),b=v())[0]?[b]:[],v(1).map(a=>[a])):[]
Explanation using the example input: v
is a helper method which returns the arrays (with parameter 1
) or values (with no parameter). We start with a = [1, [2, 3], [[4]], [[[5, 6], 7, [[[8]]]], 9]]
, which is nonempty. We filter out the arrays, giving [1]
. We then recursively call ourselves on the arrays concatenated together, which is [2, 3, [4], [[5, 6], 7, [[[8]]]], 9]
, the result being [2, 3, 9, [4, 7], [[5, 6]], [[[[8]]]]]
. We again filter out the arrays, which gives us the second term of our output, [2, 3, 9]
, however we have to be careful not to insert an empty array here. It them remains to wrap the arrays [4, 7], [[5, 6]], [[[[8]]]]
inside arrays and append them to the output, resulting in [1, [2, 3, 9], [[4, 7]], [[[5, 6]]], [[[[[8]]]]]]
.
JavaScript (ES6) 121 144 152
Edit Revised a lot, 1 byte saved thx Patrick Roberts, and 21 more just reviewing the code
Recursive function working on arrays in input and output. I don't like the request of having elements at depth 1 as single elements in output array (while greater levels are grouped as one element): [l1,l1, [l2...], [[l3...]] ]
. While this would be more direct: [ [l1...], [[l2...]], [[[l3...]]] ]
f=(l,d=0,r=[])=>l.map(v=>v[0]?f(v,d+1,r):r[d]=[...r[d]||[],v])
r.reduce((r,v,d)=>d?[...r,(n=d=>d-->1?[n(d)]:v)(d)]:v,[])
Newline added for readability.
Some notes: the line 2 is evaluated again and again at each recursive call, but only the last iteration at the end of recursion is useful.
The special handling when d==0
in line 2 takes care of the anomaly for level 1 elements.
The n
recursive function handles the array nesting in output
Test
f=(l,d=0,r=[])=>l.map(v=>v[0]?f(v,d+1,r):r[d]=[...r[d]||[],v])
&&r.reduce((r,v,d)=>d?[...r,(n=d=>d-->1?[n(d)]:v)(d)]:v,[])
console.log=x=>O.textContent+=x+'\n'
test=[
[
[1, [2,3], 4], /* -> */ [1, 4, [2,3]]
]
,[
[1, [2, 3], [[4]], [[[5, 6], 7, [[[8]]]], 9]],
// ->
[1, [2, 3, 9], [[4, 7]], [[[5, 6]]], [[[[[8]]]]]]
]
,[
[[[1]], [2, [3]], 4, [5, [6, [7, [8], [9, [[10]]]]]]],
// ->
[4, [2, 5], [[1, 3, 6]], [[[7]]], [[[[8, 9]]]], [[[[[[10]]]]]]]
]
,[
[1], /* -> */ [1]
]
,[
[1, [2], [[3]], [[[4]]], [[[[5]]]]],
// ->
[1, [2], [[3]], [[[4]]], [[[[5]]]]]
]
,[
[1, [[[[2], 3]]], [[4]]],
[1, [[4]], [[[3]]], [[[[2]]]]]
]]
test.forEach(t=>{
var i=t[0], k=t[1], r=f(i),
si=JSON.stringify(i),
sr=JSON.stringify(r),
sk=JSON.stringify(k)
console.log((sr==sk?'OK ':'KO ')+si + " => " + sr)
})
<pre id=O></pre>