# NAME
List::Flat - Functions to flatten a structure of array references
# VERSION
This documentation refers to version 0.003
# SYNOPSIS
use List::Flat(qw/flat flat_f flat_r/);
my @list = ( 1, [ 2, 3, [ 4 ], 5 ] , 6 );
my @newlist = flat_f(@list);
# ( 1, 2, 3, 4, 5, 6 )
push @list, [ 7, \@list, 8, 9 ];
my @newerlist = flat_r(@list);
# ( 1, 2, 3, 4, 5, 6, 7, 8, 9 )
my @evennewerlist = flat(@list);
# throws exception
# DESCRIPTION
List::Flat is a module with functions to flatten a deep structure
of array references into a single flat list.
# FUNCTIONS
- **flat()**
This function takes its arguments and returns either a list (in
list context) or an array reference (in scalar context) that is
flat, so there are no (non-blessed) array references in the result.
If there are any circular references -- an array reference that has
an entry that points to itself, or an entry that points to another
array reference that refers to the first array reference -- it will
throw an exception.
my @list = (1, 2, 3);
push @list, \@list;
my @flat = flat(@list);
# throws exception
But it will process it again if it's repeated but not circular.
my @sublist = ( 4, 5, 6 );
my @repeated = ( \@sublist, \@sublist, \@sublist);
my @repeated_flat = flat (@repeated);
# (4, 5, 6, 4, 5, 6, 4, 5, 6)
- **flat\_r()**
This function takes its arguments and returns either a list (in
list context) or an array reference (in scalar context) that is
flat, so there are no (non-blessed) array references in the result.
If there are any circular references -- an array reference that has
an entry that points to itself, or an entry that points to another
array reference that refers to the first array reference -- it will
not descend infinitely. It skips any reference that it is currently
processing. So:
my @list = (1, 2, 3);
push @list, \@list;
my @flat = flat(@list);
# (1, 2, 3)
But it will process it again if it's repeated but not circular.
my @sublist = ( 4, 5, 6 );
my @repeated = ( \@sublist, \@sublist, \@sublist);
my @repeated_flat = flat (@repeated);
# (4, 5, 6, 4, 5, 6, 4, 5, 6)
- **flat\_f()**
This function takes its arguments and returns either a list (in
list context) or an array reference (in scalar context) that is
flat, so there are no (non-blessed) array references in the result.
It does not check for circular references, and so will go into an
infinite loop with something like
@a = ( 1, 2, 3);
push @a, \@a;
@b = flat_f(\@a);
So don't do that. Use `flat()` or `flat_r()` instead.
When it is fed non-infinite lists, this function seems to be about
twice as fast as `flat()`.
# CONFIGURATION AND ENVIRONMENT
The functions will normally use Ref::Util to determine whether an
element is an array reference or not, but if the environment variable
$PERL\_LIST\_FLAT\_NO\_REF\_UTIL is set to a true value, or the perl
variable List::Flat::NO\_REF\_UTIL is set to a true value before
importing it, it will use its internal pure-perl implementation.
# DEPENDENCIES
It has one optional dependency, [Ref::Util](
https://metacpan.org/pod/Ref::Util).
If it is not present, a pure perl implementation is used instead.
# SEE ALSO
There are several other modules on CPAN that do similar things.
- Array::DeepUtils
I have not tested this code, but it appears that its collapse()
routine does not handle circular references. Also, it must be
passed an array reference rather than a list.
- List::Flatten
List::Flatten flattens lists one level deep only, so
1, 2, [ 3, [ 4 ] ]
is returned as
1, 2, 3, [ 4 ]
This might be, I suppose, useful in some circumstance or other.
- List::Flatten::Recursive
The code from this module works well and does the same thing as
`flat_r()`, but it seems to be somewhat slower than List::Flat (in
my testing; better testing welcome) due to its use of recursive
subroutine calls rather than using a queue of items to be processed.
Moreover, it is reliant on Exporter::Simple, which apparently does
not pass tests on perls newer than 5.10.
- List::Flatten::XS
This is very fast and is worth using if one can accept its limitations.
These are, however, significant:
- It flattens blessed array references as well as unblessed ones,
which means that any array-based objects (for example,
[Path::Tiny](
https://metacpan.org/pod/Path::Tiny) objects) will be flattened as well.
Array-based objects aren't all that common, but that's not usually
what's desired.
- Like all XS modules it requires a C compiler on the host system to be
installed, or some kind of special binary installation (e.g., ActiveState's
ppm).
- It goes into an infinite loop with circular references.
- It must be passed an array refeernce rather than a list.
It does have the potentially useful feature of being able to specify
the level to which the array is flattened (so one can ask for the
first and second levels to be flat, but the third level preserved
as references).
At one point in the development of List::Flat there was an intent to use this
module to speed up performance, but it wasn't acceptable that it flattened
objects.
It is certainly possible that there are others.
# ACKNOWLEDGEMENTS
Ryan C. Thompson's [List::Flatten::Recursive](
https://metacpan.org/pod/List::Flatten::Recursive)
inspired the creation of the `flat_r()` function.
Aristotle Pagaltzis suggested throwing an exception upon seeing
a circular reference rather than simply skipping it.
Mark Jason Dominus's book [Higher-Order Perl](
http://hop.perl.plover.com)
was and continues to be extremely helpful and informative.
[Toby Inkster](
http://toby.ink) contributed a patch to slightly
speed up `flat()` and `flat_r()`.
# BUGS AND LIMITATIONS
If you bless something into a class called 'ARRAY', the pure-perl version
will break. But why would you do that?
# AUTHOR
Aaron Priven <
[email protected]>
# COPYRIGHT & LICENSE
Copyright 2017
This program is free software; you can redistribute it and/or modify it
under the terms of either:
- the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any
later version, or
- the Artistic License version 2.0.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.