Perl optimization: inlining a function changed the results - perl

I profiled some code, and there is one function which stood out and I was wondering if there is a way to optimize it:
The function is defined as:
sub convert_arrayref {
if(ref($_[0]) eq 'ARRAY') {
return join(($_[1] || ","), #{$_[0]});
}
else {
return $_[0];
}
}
Most of the times the else block will get executed, and I was wondering if I could inline it rather than making a function call. The calling code looks as follows:
$data = convert_arrayref($data, '&')
So, what I did was change the calling code as:
if ($data eq 'ARRAY') {
$data = join('&', $data)
}
I thought this would be equivalent. However, the results are different. I am wondering if I have done something wrong here.

You get different results because you did not replicate the functionality of the if clause. You need to use ref to check if your variable is an array reference, and you need to deference the variable:
if (ref($data) eq 'ARRAY') {
$data = join('&', #{ $data })
}

Related

Replace a variable as string with results from a subroutine in perl

I am trying to replace the variable "ex" with it's string value(which it gets from subroutine "potatoex()" and put it in the definition of another variable "goodge",
not getting any syntax error but this seems to be not working out.
Please help.
sub potatoex {
my $potato="Junos: 17.4DCB";
if($potato = ~/"Junos: 17.4[a-zA-Z0-9_.]*"/) {
print "/var/home/smoketest/dhcpv6.pl.28709.log";
}
}
main :
{
my $ex= potatoex();
my $goodge= "Apurva $ex Arnav";
print $goodge;
}
CURRENT O/P : /var/home/smoketest/dhcpv6.pl.28709.logApurva 1 Arnav
EXPECTED O/P: Apurva /var/home/smoketest/dhcpv6.pl.28709.log Arnav
Thanks,
Apurva
You are printing from your subroutine instead of returning the value from it. Try using return in potatoex.
sub potatoex {
my $potato = q{Junos: 17.4DCB};
my $returnVal = '';
if( $potato =~ /Junos: 17\.4[a-zA-Z0-9_.]*/ ) {
$returnVal = q{/var/home/smoketest/dhcpv6.pl.28709.log};
}
$returnVal;
}
{
my $ex = potatoex();
my $goodge = qq{Apurva $ex Arnav};
print $goodge;
}
While you could use return in an if block above (instead of print), I instead decided to use a variable, which will always return either the value you are trying to or an empty string. You could explicitly state the return return returnVal;, but it isn't required as perl allows implicit returns (make note of this and figure out if it should fit in your best practices or not).

Access an array item in Perl after generating that array

Hello I want to access an specific array item based in a condition previously checked. I leave the code here:
elsif (scalar(#{$boss->bosses}) > 1) {
foreach my $pa (#{$boss->bosses}) {
my $p = My::Model::Group->new(id => $pa->group_id);
push(#$groups, $p);
$valid_pass = 1 if ($pa->checkPassword($self->param('password')));
}
if ($valid_pass) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
}
}
What I want to do is, if that if in the array that comes, I check if the password is correct, so if it's correct, then I want to take the id and the group_id of the array item to use it in a function to be able to log them in.
Your for loop is doing two things at once: producing a list of My::Model::Group objects in #$groups, and finding the first boss whose password checks out.
I suggest that you split them up into two clear operations, and the List::Util modules first operator is ideal for the second task
Here's how it would look. I've extracted the result of the method call $boss->bosses into a variable $bosses to avoid repeated calls to the method
Note that you don't need to apply scalar to an array when checking its size. The > and all the other comparators impose scalar context anyway
I've taken much of my code from your question, and I'm a little concerned that you extract values for $pa_id and $pa_partner_id and then just discard them. But I imagine that you know what you really want to do here
use List::Util 'first';
my $bosses = $boss->bosses;
if ( ... ) {
...;
}
elsif ( #$bosses > 1 ) {
#$groups = map { My::Model::Group->new( id => $_->group_id ) } #$bosses;
my $password = $self->param( 'password' );
my $pa = first { $_->checkPassword( $password ) } #$bosses;
if ( $pa ) {
my $pa_id = $pa->id;
my $pa_partner_id = $pa->group_id;
}
else {
...;
}
}

How can I return a whole hash map in Perl?

I have a hash called
%values
Now I want to return the whole hash in a subroutine
sub getvalues {
return $values;
}
But then I got an error, because $value needs a definition and my program stops. If I'm using
sub getvalues {
return %values;
}
it seems to work, but my program is very slow and don't get further... So how can I return the whole map?
It would be nice to return the hash reference instead of hash,what you need to do is
First stote the hash into the hash ref then return it like
sub getvalues {
my %values = (test => "SO");
my $values = \%values;
return $values;
}

Can't get values when looping over an array of arrays

I created an array like so:
while(#results = $execute->fetchrow())
{
my $active = 'true';
if($results[1] == 0)
{
$active = 'false';
}
my #campaign = ($results[0], $active);
push(#campaign_names, #campaign);
}
Later, when I need to access the name of the campaign (which is the first element of the campaign array), I can't seem to extract it. What is the proper syntax?
foreach $campaign (#campaign_names)
{
print ????;
}
Thanks!
The problem is you're pushing an array onto the end of #campaign_names, when what you want is an array reference. Here's how I'd write it:
while(#results = $execute->fetchrow())
{
my $active = $results[1] ? 'true' : 'false';
push #campaign_names, [ $results[0], $active ];
}
# later
foreach my $campaign( #campaign_names )
{
my $name = $campaign->[0];
my $active = $campaign->[1];
}
I've cleaned it up a bit by using a ternary conditional (?:) to figure out the value of $active. The [ ... ] constructs an anonymous array reference (a scalar pointing to an array) which is then pushed onto #campaign_names.
When we loop over those later, two important things to notice are that we use my in the loop variable to keep it local to the loop block, and that we use -> to dereference the elements in the array pointed to by the array reference.
That's not creating an array of arrays. my #campaign = ($results[0], $active); push(#campaign_names, #campaign); flattens and pushes $results[0] and $active into the #campaign_names array. Instead, push an arrayref:
my #campaign = ($results[0], $active);
push(#campaign_names, \#campaign);
or
my $campaign = [$results[0], $active];
push(#campaign_names, $campaign);
Arrays can only hold scalar values.
You'll want to refer to perldsc as you learn (perldoc perldsc, http://perldoc.perl.org/perldsc.html)

Perl: How to check what is being returned from a subroutine

I have a subroutine that will return two hashes when all goes well. But the sub checkouts output of command and if it matches a certain pattern, it returns with "-1". Is there anyway to check the return of the subroutine from where I called it?
Kinda like:
if (RETURN_VALUE == -1){
do something}
else
go as normal with the hashes
How could one function return two hashes?
If you mean hashrefs, the check would be quite simple:
my ($h1,$h2) = myFunction();
if ( !ref($h1) || (ref($h1) ne "HASH"))
{
die 'error';
}
You function should return references to the two hashes on success and nothing upon failure. Then you can just check the truth value of the function call.
sub myfunc {
my %hash1;
my %hash2;
return (\%hash1, \%hash2);
}
my $ref1;
my $ref2;
unless (($ref1, $ref2) = myfunc()) {
print "Something went wrong\n";
} else {
print "OK\n";
}
If you return two (or any number for that matter) hashes from a subroutine, the result will be a single hash. You will not be able to separate the original hashes from the result in a normal manner. Returning hash references will not exhibit this problem.
Suppose foo() returns two hash references when the pattern is matched and returns -1 when it does not match.
my ( $value_1, $value_2 ) = foo;
if ( $value_1 == -1 ) {
# pattern did not match
}
else { # for strict checks: elsif ( ref $value_1 eq 'HASH' && ref $value_2 eq 'HASH' ) {
# pattern matched
}