http://qs321.pair.com?node_id=11106621

With AoAs something like:
my $ar = [ [ 'HEAD_goes_here', 'BODY_here' ], [ 'FOOT', 'FOOT', 'FOOT', 'FOOT' ] ];
written as a template with the literals as documentation. After the not-finding and the not-thinking, I wrote a sub to walk AoAs and extract the references to the scalar elements. Doing it by hand, one might write:
my $scalars_flattened = [ \$ar->[0][0], \$ar->[0][1], \$ar->[1][0], \$ar->[1][1], \$ar->[1][2], \$ar->[1][3] ];
Its gist:
my @flat = @{$_[0]}; while ( List::Util::any { 'ARRAY' eq ref $_ } @flat ) { @flat = map { 'ARRAY' eq ref $_ ? \(@$_) : \$_ } @flat; @flat = map { 'REF' eq ref $_ ? $$_ : $_ } @flat; }
Fortunately only in testing did I find the less helpfully shaped templates like:
$ar = [ 'HEAD', 'BODY', [ 'FOOT', 'FOOT', 'FOOT', 'FOOT'], ];
I would die if I had one like that.

Be well,
rir

Replies are listed 'Best First'.
Re: "Nonliteral literal" is just an expression.
by choroba (Cardinal) on Sep 24, 2019 at 10:04 UTC
    This calls for recursion.
    #!/usr/bin/perl use warnings; use strict; use List::Util qw{ any }; sub flatten { my ($struct) = @_; if (ref [] eq ref $struct) { return map flatten($_), @$struct } elsif (ref \\"" eq ref $struct) { return $$struct } else { return \$struct } } use Test::More tests => 2; my $ar = [ [ 'HEAD_goes_here', 'BODY_here' ], [ 'FOOT', 'FOOT', 'FOOT', 'FOOT' ] ]; my @flat = @$ar; while ( any { ref [] eq ref $_ } @flat ) { @flat = map { ref [] eq ref $_ ? \(@$_) : \$_ } @flat; @flat = map { ref \\"" eq ref $_ ? $$_ : $_ } @flat; } is_deeply \@flat, [map \$_, qw[ HEAD_goes_here BODY_here FOOT FOOT FOOT FOOT ] ]; is_deeply [flatten($ar)], \@flat;

    What's wrong with the "less helpful" template? Both approaches return the same result.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      What's wrong with the "less helpful" template?

      That is the interesting part. And it surprises me that I have never been caught by this in my years of occasional programming. I am still chewing on that aspect.

      Both approaches return the same result.

      Not quite, your tests are flawed. I wanted references to the same memory objects ("thingie" is out of style?) so running @flat through both your and my code is suspect on its face. When I comment out the while loop I don't get a happy result.

      On a side note: In the "not-thinking" part I started on a recursive solution; when I hit some snags and applied some thought map seemed a clear win. I should study the methods to go from one to the other: iter. vs. recurs.

      Using a shorter array:

      my $ar = [ [ 'a', ], [ 'b, 'c', ], ]; my $flat = flat( $ar ); print Dumper $ar, $flat;
      should yield:
      $VAR1 = [ [ 'a' ], [ 'b', 'c' ] ]; $VAR2 = [ \$VAR1->[0][0], \$VAR1->[1][0], \$VAR1->[1][1] ];
        Ah, now I understand! A small change in the flatten subroutine should fix that.
        sub flatten { my ($struct) = @_; if (ref [] eq ref $struct) { return map flatten($_), @$struct } else { return \$_[0] # <- We need to use the alias, not a copy. } }
        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]