CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
alternative , faster and optimal approach to if condition

 



Tejas
User

Nov 15, 2013, 2:52 AM

Post #1 of 14 (1519 views)
alternative , faster and optimal approach to if condition Can't Post

Below is the code,
Can anyone suggest me the alternative approach to the below code
if($ppcl_id == 1)
{
print US_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";
}
elsif($ppcl_id==7)
{
print CA_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n";
}
elsif($ppcl_id==526970)
{
print BR_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";
}
elsif ($ppcl_id==771770)
{
print MXN_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n";
}
elsif($ppcl_id == 6)
{
print JP_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";
}
elsif($ppcl_id == 111172)
{
print AUS_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";
}
As i think its really big and also slow


2teez
Novice

Nov 15, 2013, 3:45 AM

Post #2 of 14 (1517 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

You can use a Dispatch table, instead of long if/if else statements. Since you have unique $appcl_id, you can use it as key to a hash variable something like:

Code
my %table = ( 
1 => sub{ ...},
7 => sub {...},
526970 => sub {...},
771770 => sub {...},
...
);



BillKSmith
Veteran

Nov 15, 2013, 6:15 AM

Post #3 of 14 (1512 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

Use the '?' operator. Lexical ($) file handles are required, but you should be using them anyhow.


Code
use strict; 
use warnings;
my ($custid, $date, $esid, $amount, $currency, $ppcl_id);

# Use lexical filehandles.
open my $US_BACKFILL, '>', 'usfile.txt' or die "$!";
open my $CA_BACKFILL, '>', 'cafile.txt' or die "$!";
open my $BR_BACKFILL, '>', 'brfile.txt' or die "$!";

my $BACKFILL = $ppcl_id == 1 ? $US_BACKFILL
: $ppcl_id == 7 ? $CA_BACKFILL
: $ppcl_id == 526970 ? $BR_BACKFILL
: undef
;
if (defined $BACKFILL) {
print {$BACKFILL} "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";
}

Good Luck,
Bill


FishMonger
Veteran / Moderator

Nov 15, 2013, 6:40 AM

Post #4 of 14 (1512 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

I am a big proponent for using dispatch tables and would recommend using one here. However, a benchmark test will show that the messy if/elsif/else chain is slightly faster, but not enough to worry about.

The only difference I see in each of those cases is what is prepended to _BACKFILL to determine which filehandle to use. If that's the case, then the most optimal/fastest approach would be to use a simple hash lookup instead of a dispatch table or the messy if/elsif/else chain.

You're currently using bareword filehandles, which is frowned upon. It's best practice to use lexical vars for filehandles.

Here's an example.

Code
my %BACKFILL; 

open $BACKFILL{1}, '>', 'US_backfill.txt' or die "failed to open 'US_BACKFILL.txt' $!";
open $BACKFILL{6}, '>', 'JP_BACKFIll.txt' or die "failed to open 'JP_BACKFILL.txt' $!";
open $BACKFILL{7}, '>', 'CA_backfill.txt' or die "failed to open 'CA_BACKFILL.txt' $!";

# the braces around the filehandle are required in this case
print {$BACKFILL{$ppcl_id}} "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";


When using either this approach or the dispatch table, you'd want to add a couple additional lines that make sure that the value in $ppcl_id has a corresponding key in the hash.


Tejas
User

Nov 15, 2013, 8:21 AM

Post #5 of 14 (1508 views)
Re: [FishMonger] alternative , faster and optimal approach to if condition [In reply to] Can't Post

hi
my $GB_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-GB"; #-$time";
my $DE_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-DE";
my $FR_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-FR";
my $ES_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-ES";
my $IT_BACKFILL = "$pwd/BADDEBT-BACKFILL_FILE-IT";


my $GB_MISSING_ESID = "$pwd/BADDEBT-MISSING_ESID_FILE-GB";
my $DE_MISSING_ESID = "$pwd/BADDEBT-MISSING_ESID_FILE-DE";
my $FR_MISSING_ESID = "$pwd/BADDEBT-MISSING_ESID_FILE-FR";
my $ES_MISSING_ESID = "$pwd/BADDEBT-MISSING_ESID_FILE-ES";
my $IT_MISSING_ESID = "$pwd/BADDEBT-MISSING_ESID_FILE-IT";

open (GB_MISSING_ESID, "> $GB_MISSING_ESID") or die "unable to open output file: $!";
open (DE_MISSING_ESID, "> $DE_MISSING_ESID") or die "unable to open output file: $!";
open (FR_MISSING_ESID, "> $FR_MISSING_ESID") or die "unable to open output file: $!";
open (ES_MISSING_ESID, "> $ES_MISSING_ESID") or die "unable to open output file: $!";
open (IT_MISSING_ESID, "> $IT_MISSING_ESID") or die "unable to open output file: $!";
open (GB_BACKFILL, "> $GB_BACKFILL") or die "unable to open output file: $!";
open (DE_BACKFILL, "> $DE_BACKFILL") or die "unable to open output file: $!";
open (FR_BACKFILL, "> $FR_BACKFILL") or die "unable to open output file: $!";
open (ES_BACKFILL, "> $ES_BACKFILL") or die "unable to open output file: $!";
open (IT_BACKFILL, "> $IT_BACKFILL") or die "unable to open output file: $!";

I have opened all the files first and then

while (my $line=<BADDEBT>) {
chomp;
my @row = split (",",$line);

$date = $row[1];
$esid = $row[4];
$amount = $row[5];
$ppcl_id=$row[8];
$currency=$row[6];
#send the esid to query for retriving customerid
my @cust_idd = $session->array_for_cursor('get_digital_bad_debt_data',0,$esid);
chomp;
$custid = $cust_idd[0];
if ($custid)
{
if($amount eq 0 )
{
print "For $esid -> Amount is $amount \n";
print ZERO_LOG "$custid|$date|391|$esid|$amount|$currency|$ppcl_id|8\n"
}
else {
if($ppcl_id == 3)
{
print GB_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";
}
elsif($ppcl_id==4)
{
print DE_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n";
}
elsif($ppcl_id==5)
{
print FR_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";
}
elsif ($ppcl_id==44551)
{
print ES_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n";
}
elsif($ppcl_id == 35691)
{
print IT_BACKFILL "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";

So I need to change all and apply what ever is suggested.


FishMonger
Veteran / Moderator

Nov 15, 2013, 8:36 AM

Post #6 of 14 (1504 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post


Quote
So I need to change all and apply what ever is suggested.

Yes

I suggest using the hash to store the filehandles like my example. It would be the cleanest and most efficient.

I also suggest that you try to avoid the all uppercase vars, they are harder to read than lowercase or camel case.


Tejas
User

Nov 15, 2013, 8:38 AM

Post #7 of 14 (1503 views)
Re: [FishMonger] alternative , faster and optimal approach to if condition [In reply to] Can't Post

This works awesome, but how can a hash work like a file handle..
Please Explain me , am a beginner and need to understand this.
This code works perfectly :)

can u plese explain me what does the below line do

print {$BACKFILL{$ppcl_id}} "$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8\n ";

As per my understanding , $BACKFILL{$ppcl_id} GETS CONVERTED TO $BACKFILL{1} nad that file is written.
But i think there is more to undertand in this line (with respect to hash).Can u please explain me.

Thanks in advance


FishMonger
Veteran / Moderator

Nov 15, 2013, 8:41 AM

Post #8 of 14 (1501 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

Another cleanup suggestion would be to replace this:

Code
my @row = split (",",$line); 

$date = $row[1];
$esid = $row[4];
$amount = $row[5];
$ppcl_id=$row[8];
$currency=$row[6];


with this:

Code
my ($date, $esid, $amount, $urrency, $ppcl_id) = (split /,/, $line)[1,4,5,6,8];



Tejas
User

Nov 15, 2013, 8:43 AM

Post #9 of 14 (1499 views)
Re: [FishMonger] alternative , faster and optimal approach to if condition [In reply to] Can't Post

also

open $BACKFILL{1}, '>', 'US_backfill.txt' or die "failed to open 'US_BACKFILL.txt' $!";
open $BACKFILL{6}, '>', 'JP_BACKFIll.txt' or die "failed to open 'JP_BACKFILL.txt' $!";
open $BACKFILL{7}, '>', 'CA_backfill.txt' or die "failed to open 'CA_BACKFILL.txt' $!";

how does this work and how is it creating an output file in PWD.
Is it just a file name or any hash logic attached to it..
Thanks


FishMonger
Veteran / Moderator

Nov 15, 2013, 9:04 AM

Post #10 of 14 (1489 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

When opening/creating a filehandle you can either use a bareword typeglob, which is what you were doing, or you can use a var for the filehandle, which is what I am doing.

The majority of the time you'll be (or should be) using a lexical scalar var for the filehandle, but if you have multiple filehandles you can store them in a more complex data structure such as an array or a hash.

If you use an array or hash for the filehandles, then it must use { } braces around the filehandle in the print statemnt. When using a simple scalar, those braces are optional, but probably a good idea to still use.

For the gory details, please read these 2 perldocs.
perldoc perlopentut
http://perldoc.perl.org/perlopentut.html

perldoc -f open
http://perldoc.perl.org/functions/open.html


(This post was edited by FishMonger on Nov 15, 2013, 9:05 AM)


Laurent_R
Veteran / Moderator

Nov 15, 2013, 11:04 AM

Post #11 of 14 (1481 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

I agree that a dispatch table would be much better that the long if/elsif thing. Using some moderately advanced Perl concepts such as anonymous code references, function factories and closures can make the code far far shorter. Something like this:


Code
my %dispatch; 
$dispatch{3} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-GB");
$dispatch{4} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-DE");
$dispatch{5} = create_func( "$pwd/BADDEBT-BACKFILL_FILE-FR");
# etc for the other files
# now, your files are opened and the %dispatch hash contains references to functions that know where to print
# no need to mess up with numerous file names and file handler names

while (my $line=<BADDEBT>) {
# all your code until the large if/elsif thing
# ...
$dispatch{$ppcl_id}->("$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8");
# (that's it!)

sub create_func {
my $file = shift;
open my $FH, ">", $file or die "cound not open $file $!";
return sub {
my $to_be_printed = shift;
print $FH $to_be_printed, "\n";
}
}


BTW, an additional error in your code: chomp without argument will not chomp your $line variable.


(This post was edited by Laurent_R on Nov 15, 2013, 11:37 AM)


Tejas
User

Nov 20, 2013, 11:25 PM

Post #12 of 14 (1448 views)
Re: [Laurent_R] alternative , faster and optimal approach to if condition [In reply to] Can't Post

Below is the code using dipach tabale, based on the coditions in the code,do i need to use 3 dispatch tables..
1.Zero Log
2.Backfill
3.Missing


while (my $line = <BADDEBT>)
{
chomp();
my ($date, $esid, $amount, $urrency, $ppcl_id) = (split /,/,$line)[1, 4, 5, 6, 8];
if ($amount eq 0)
{
print ZERO_LOG "$custid|$date|391|$esid|$amount|$currency|$ppcl_id|8\n";
}
else
{
($custid) = $session->array_for_cursor('get_digital_bad_debt_data', 0, $esid);
if ($custid)
{
# the braces around the filehandle are required in this case
$dispatch{$ppcl_id}->("$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8");
$Total_Amnt_Hash{Backfilled_ESID}{$ppcl_id} += $amount;
}
else
{
print {$MISSING_ESID{$ppcl_id}} "$date|$esid|$amount|$currency|$ppcl_id\n ";
}
}
}


Tejas
User

Nov 21, 2013, 1:37 AM

Post #13 of 14 (1446 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

And how should i close files opened using dispach hash

In Reply To
Below is the code using dipach tabale, based on the coditions in the code,do i need to use 3 dispatch tables..
1.Zero Log
2.Backfill
3.Missing


while (my $line = <BADDEBT>)
{
chomp();
my ($date, $esid, $amount, $urrency, $ppcl_id) = (split /,/,$line)[1, 4, 5, 6, 8];
if ($amount eq 0)
{
print ZERO_LOG "$custid|$date|391|$esid|$amount|$currency|$ppcl_id|8\n";
}
else
{
($custid) = $session->array_for_cursor('get_digital_bad_debt_data', 0, $esid);
if ($custid)
{
# the braces around the filehandle are required in this case
$dispatch{$ppcl_id}->("$custid|$date|391|$esid|-$amount|$currency|$ppcl_id|8");
$Total_Amnt_Hash{Backfilled_ESID}{$ppcl_id} += $amount;
}
else
{
print {$MISSING_ESID{$ppcl_id}} "$date|$esid|$amount|$currency|$ppcl_id\n ";
}
}
}


Quote


Laurent_R
Veteran / Moderator

Nov 21, 2013, 3:29 PM

Post #14 of 14 (1435 views)
Re: [Tejas] alternative , faster and optimal approach to if condition [In reply to] Can't Post

The files will be automatically closed as soon as the file handler goes out of lexical scope, or at the latest when the program will terminate. Yes, I usually prefer to explicitly close files, and it can't be done here very simply, but I do not see this as being bad if there is a good mastery of scope.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives