Reputation: 396
Consider following script:
use strict;
use Data::Dumper;
my @arr=('1A','2A');
my $arr_ref=['1','2'];
sub routine1
{
my @arr=@_;
print Dumper(\@arr);
}
routine1(@arr,'one_A');
sub routine2
{
my $arr_ref=[@_];
print Dumper($arr_ref);
}
routine2($arr_ref,'one');
routine1
is using @arr
and routine2 is using $arr_ref
.
routine1
prints the following:
$VAR1 = [
'1A',
'2A',
'one_A'
];
routine2
prints following:
$VAR1 = [
[
'1',
'2'
],
'one'
];
I want to continue using @_
and arr_ref
in routine2
but want to come up with below output:
$VAR1 = [
'1',
'2'
'one'
];
Can someone suggest the way out?
Upvotes: 1
Views: 177
Reputation: 93765
Just wrote this the other day at work.
sub flatten {
return map { ref($_) ? flatten(@{$_}) : ($_) } @_;
}
Upvotes: 1
Reputation: 20280
Using the function ref
you can see if a scalar is a reference (and if so, which type). In a simplistic case where only array references will be passed you can simply use this to flatten the inputs.
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
sub test {
my @arr = map { ref() ? @$_ : $_ } @_;
print Dumper \@arr;
}
test( ['a', 'b'], 1 );
As a side benefit, this code will die with a message if a reference to another type is passed, since you attempt to deference as an array. If you need to handle more, you will need to check the reference type. This starts to build in complexity quickly.
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
sub test {
my @arr = map {
my $type = ref;
if ( ! $type ) {
$_;
} elsif ( $type eq 'ARRAY' ) {
@$_;
} elsif ( $type eq 'HASH' ) {
%$_;
} else {
()
}
} @_;
print Dumper \@arr;
}
test( ['a', 'b'], { p => 'q' }, 1 );
By returning an empty list for other reference types I silently ignore all other reference types. Or perhaps you would rather force stringification on other reference types.
...
} else {
"$_";
}
...
test( ['a','b'], sub{}, bless({},'MyClass'), 1 );
Of couse which of these handlings to use depends on you use case.
Upvotes: 3
Reputation: 126742
This program shows a subroutine flatten
that will flatten a mixed list of simple data and array references, nested to any level.
use strict;
use warnings;
use Data::Dump;
my @arr = qw/ 1A 2A /;
my $arr_ref = [1, 2];
sub flatten;
routine1(@arr, 'one_A');
routine2($arr_ref, 'one');
sub routine1 {
my @arr=@_;
dd \@arr;
}
sub routine2 {
my $arr_ref = [flatten @_];
dd $arr_ref;
}
sub flatten {
my $i = 0;
while ($i < @_) {
my $item = $_[$i];
if (ref $item eq 'ARRAY') {
splice @_, $i, 1, @$item;
}
else {
++$i;
}
}
@_;
}
output
["1A", "2A", "one_A"]
[1, 2, "one"]
Upvotes: 0