Home > Back-end >  How can I use "map" in "perl" to return a hash reference whose key is looked up
How can I use "map" in "perl" to return a hash reference whose key is looked up

Time:10-08

I've searched other many Stack questions on map however this requirement is particular and well try as I might I cannot quite get the solution I am looking for, or I think that does exist.

This question is simply about performance.

As limited, background, this code segment used in decoding incoming tokens so it's used on every web request and therefore the performance is critical and I know "map" can be used so want to use it.

Here is a trimmed down but never the less fully working code segment which I am currently using and works perfectly well:

use strict;
use Data::Dumper qw (Dumper);

my $api_token = { array => [ 'user_id', 'session_id', 'expiry' ], max => 3, name => 'session' };
my $token_got = [ 9923232345812112323, 1111323232000000465, 1002323001752323232 ];

my $rt;
for (my $i=0; $i<scalar @{$api_token->{array}}; $i  ) {
  $rt->{$api_token->{array}->[$i]} = $token_got->[$i];
}

$rt->{type} = $api_token->{name};
print Dumper ($rt) . "\n";

The question is: What is the absolute BEST POSSIBLE PERL CODE to replicate the foreach statement above in terms of performance?

I thank you in-advance and apologize if there is some duplicate somewhere but well this is specific to me at least.

CodePudding user response:

Looks like you only need a hash slice

my %rt;

@rt{ @{ $api_token->{array} } } = @$token_got;

Or, if the hash reference is needed

my $rt;

@{ $rt } { @{ $api_token->{array} } } = @$token_got;

or with the newer postfix dereferencing, on both array and hash slices, perhaps a bit nicer

my $rt;

$rt->@{ $api_token->{array}->@* } = @$token_got;

One can also do it using List::MoreUtils::mesh, and in one statement

my $rt = { mesh @{ $api_token->{array} }, @$token_got };

or with pairwise from the same library

my $rt = { pairwise { $a, $b } @{ $api_token->{array} }, @$token_got };

These go via C code if the library gets installed with List::MoreUtils::XS.


Benchmarked all above, with the tiny datasets from the question (realistic though?), and whatever implementation mesh/pairwise have they are multiple times as slow as the others.

On an old laptop with v5.26

              Rate use_pair use_mesh use_href use_post use_hash
use_pair  373639/s       --     -36%     -67%     -67%     -68%
use_mesh  580214/s      55%       --     -49%     -49%     -51%
use_href 1129422/s     202%      95%       --      -1%      -5%
use_post 1140634/s     205%      97%       1%       --      -4%
use_hash 1184835/s     217%     104%       5%       4%       --

On a server with v5.36 the numbers are around 160%--170% against pairwise (with mesh being a bit faster than it, similarly to above)

Of the others, on the laptop the hash-based one is always a few percent quicker, while on a server with v5.36 they are all very close. Easy to call it a tie.


The following is edit by OP, who timed a 61% speedup (see comments)

CHANGED CODE:

@rt{ @{ $api_token->{array} } } = @$token_got; ### much faster onliner replaced the loop. @zdim credit
  • Related