How to handle nested array with >> and return a flat array?

make $<pnamelist>.map(*.made.Slip)

When you slip a list of values in a map, they get flattened.

Using >>. is nice in many cases, but personally I prefer .map as it allows for more flexibility.


TL;DR Flatten using positional subscripting. For your example, append [*;*] or [**] to $<pnamelist>>>.made. You'll get the same result as Liz's solution.

Why use this solution?

Liz is right that map and relatives (for, deepmap, duckmap, nodemap, and tree) are more flexible, at least collectively, and combining them with .Slip can be just the ticket.

But I often I find it cognitively simpler to use these tools, and others, including hypers, to create whatever data structure, without worrying about .Sliping, and then just flatten the result at the end by just appending [*;*...] or [**] as explained below.

Last but not least, it's simple and succinct:

method port ($/) { make $<pnamelist>>>.made[**] }
                                           ^^^^

Flattening N levels deep with [*;*...]

The general approach for flattening N levels deep works today as @Larry always intended.

The first Whatever strips away the outer array; each additional Whatever, separated by a ;, peels away another inner level of nesting. For your current example two Whatevers does the job:

method port ($/) { make $<pnamelist>>>.made[*;*] }
                                           ^^^^^

This yields the same result as Liz's solution:

(a b c d)

If you want the end result to have an outer array, just add it to the end result wherever you think appropriate, eg:

method port ($/) { make [ $<pnamelist>>>.made[**] ] }

Bulldozing with [**]

If you want to bulldoze a nested array/list, peeling away all nesting no matter how deep, you could just write more *;s than you can possibly need. Any extras won't make any difference.

But the desire to bulldoze is natural enough, and comes up often enough, that it makes sense to have an operation that does it without needing a hacky notion like "just write lots of *;".

So it should come as no surprise that @Larry specified such a bulldozing operation a decade or so ago. It's nicely consistent with the rest of Raku's feel, using a HyperWhatever (**) as an indexing value.

But trying it:

method port ($/) { make $<pnamelist>>>.made[**] }
                                           ^^^^

currently yields:

HyperWhatever in array index not yet implemented. Sorry.

Fortunately one can very easily "fake" it:

sub postfix:< [**] > (\lhs) { gather lhs.deepmap: *.take }

The body of the postfix comes from here.

With this in place then changing the [*;*] to [**] will work for your example but will continue to work no matter how deeply nested its left hand side is.

And presuming HyperWhatever in array index is one day implemented as a built in, one will be able to remove the postfix definition and any code using it will work without it -- and, presumably, get a speedup.

Tags:

Arrays

Raku