PrePAN

Sign in to PrePAN

List::Flat Another module to flatten an arrayref or list that may contain arrayrefs

Good

Synopsis

use List::Flat(qw/flat flatx/);

my @list = ( 1, [ 2, 3, [ 4 ], 5 ] , 6 );

my @newlist = flatx(@list);
# ( 1, 2, 3, 4, 5, 6 )

push @list, [ 7, \@list, 8, 9 ];
my @newerlist = flat(@list);
# ( 1, 2, 3, 4, 5, 6, 7, 8, 9 )

Description

I was unhappy with the several modules on CPAN I could find that do the relatively simple task of flattening a deep structure of array references into a single flat list, so I wrote another one.

Or rather, another two: one that handles circular references (flat) and one that doesn't (flatx). I suspect flatx is a terrible name but I couldn't think of one that wasn't something like "flat_unsafe" and that didn't encourage its use indiscriminately.

Thoughts welcome. Thanks.

Comments

Maybe submit this as a pull request to List::Util or List::MoreUtils?
I see a related open ticket (that points to even more requests for the feature) on the latter here: https://rt.cpan.org/Public/Bug/Display.html?id=106399
Presumably the difference between handling or not handling circular references is speed? In which case, maybe “flat_fast”?

Also, I don’t know that just ignoring a circular reference (i.e. it disappears from the output) is always the right thing. Maybe another variant that just detects circular references and croaks when it finds one?
Well, I certainly think a flat function would be appropriate for /List::.*utils?/i, and would be happy to contribute, but there are several reasons why I didn't think that was the best next step.

* I don't really understand what's going on with List:::MoreUtils and List::SomeUtils and the recent decoupling of the List::MoreUtils::XS distribution from List::MoreUtils, and it seems that there's a lot of disagreement around it, and I'd just as soon not wade into that morass.

* All those modules provide XS versions as well as pure perl versions of their functions, and I am not in a position to write an XS version. (I don't know much more about XS than how to spell it.)

* There are (at least) two different versions of flat() and I wasn't sure which one would be most appropriate to include, and it didn't seem likely that more than one would be included.

And honestly, that this has been on the List::MoreUtils to-do list for 11 years doesn't fill one with confidence that this will be included any time soon. (Not that I can't relate, but...) It's not as though working perl code hasn't been out there for a long time in List::Flatten::Recursive. (You could argue this could be just an update to that, but since in fact the implementation here isn't recursive, it seems wrong.)

Actually, originally I had called it "flat_fast", and then I kept screwing up and typing "fast_flat", and sometimes accidentally "flat_flat" and "fast_fast", and by the end I couldn't remember without looking which one I had actually intended to call it. Although I suppose I'm biased in that I'm trying to excuse my own mistakes, I think this is genuinely easy to mix up given the relative similarity of the two words. I guess I could call it faster_flat or something. I had also been thinking that pointing out the downside would be more helpful than the upside. "flat_nocycle"? "flat_c"?

As for the croak-on-circular: to be honest, I didn't really think about this in any great depth (so to speak). LFR implemented it this way, and just promised that "each non-list element in the data structure should appear at least once in the output." So I did too. Croaking seems like a reasonable alternative. That's one more name to come up with, though...
How about List::Flatten, exporting a function flatten_list?

You could provide two functions, and have an import option to control which you get:

use List::Flatten -nocycle 'list_flatten';

Or something like that.
As noted in the List::Flat documentation, there's another module called List::Flatten already.

Please sign up to post a review.