Cannot have plain array after removal ones in multi dimensional array

Viewed 89

How do we have plain array after ones in multi dimensional array are removed ?

@p=();
my @l=([9,7],[3,4]);

push(@p,['FOO',[@l]]);
push(@p,['BAR',[[8,0]]]);
splice(@$_,0,1) for @p;
print "\n",@$_ for @p;

ARRAY(0x5624cf01e340)
ARRAY(0x5624cf028d78)

How do we have it simple/plain 2D array with number of 1x2 size on inner/2nd dimensional one. In other words, how linearize it to such?

1 Answers

Have to de-reference elements which are array-references, and copy data. For a single level:

@ary = map { ref eq "ARRAY" ? @$_ : $_ } @ary;

The ref builtin by default takes $_. Also consider using reftype from Scalar::Util, instead. Then also look into is_arrayref from Ref::Util. In simple and straighforward cases the builtin is fine.

In case there are deeper levels use the above on each level. For the question's quest, to retain one level of nesting from the two-level deep input data:

for my $elem (@p) { 
    @$elem = map { ref eq "ARRAY" ? @$_ : $_ } @$elem;
}

Since $elem aliases the current element of @p this code changes the array in place.

If there are further levels, of possibly varying depth, can handle that either recursively or iteratively. Crude implementations:

Recursive:

sub flatten_recurse { 
    return map { ref eq 'ARRAY' ? flatten_recurse(@$_) : $_ } @_ 
}

This could be expensive on large data structures (but worry only if that is indeed the case).

Iterative:

sub flatten_iter { 
    my @deque = @_; 
    my @flat;
    while (@deque) {
        my $front = shift @deque;
        if (ref($front) eq 'ARRAY') {
            unshift @deque, @$front;
        } else {
            push @flat, $front;
        }
    }   
    return \@flat;
}

Here one can also use pop and push, in varying combinations. The above keeps the order, as much as that makes sense when reducing a complex structure to a flattened one.

If there are yet other complexities, like other types of references (themselves containing arrayrefs to be unpacked), then this need be adjusted accordingly. One would also need to add checks, in particular for circular references. See for instance this SO page and this perlmonks page.

Related