# approach to calculating pay

#### Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on
This isn't strictly Perl question, but I've implemented this in Perl, and w
ill re-implement it in Perl.

I have several contracts to build about five times a year. Among other prov
isions, the 'contract price' is one of the provisions. While some are negot
iated (and therefore beyond my ken) most can be calculated. I have built a
function to calculate the pay, to which I pass about nine different paramet
ers, and it returns a discrete integer, the 'contract price.' Rather than d
escribe it, there is some semi-pseudo code below. As you will note, it cons
ists of a large number (almost 100) of if-elsif statements.

Question: can someone recommend a better approach?

Thanks, CC.

my %contracts = get_contract_info_from_database();
foreach my \$contract (keys %contracts)
{
#initialize about 20 different variables that constitute the contract ter
ms
my (\$site, \$rank, \$experience, \$ftptstat, \$jobtype, \$level ... ) = pars
e_row_from_hash(\$contracts{\$contract);
\$contract_price = calculate_contract_price(\$site, \$rank, \$experience, \$
ftptstat, \$jobtype, \$level ...);
#build and print each contract
}

sub calculate_contract_price
{
my (\$site, \$rank, \$experience, \$ftptstat, \$jobtype, \$level ... ) = @_;
my \$contract_price = 0;
if (\$jobtype eq 'a')
{
if (\$level == 1)
{
if (\$rank eq 'A')
{
# etc for the rest of the nine parameters until, at the bottom, I have this
:
# \$contract_price = \$hours * \$production * 1288;
# (1288 constitutes the approved price for the work to be performed at the
#   particular level, rank, site, time status, job type, etc.
}
elsif (\$rank eq 'B')
{

}
elsif (\$rank eq 'C')
{

}
else { warm "ERROR in rank, \$rank\n"; }
}
elsif (\$level == 2)
{

}
elsif (\$level == 3)
{

}
else { warn "ERROR in level: \$level\n"; }
}
elsif (\$jobtype eq 'b')
{

}
elsif (\$jobtype eq 'b')
{

}
else { warn "ERROR in jobtype: \$jobtype\n";
return \$contract_price;
}

## Re: approach to calculating pay

Please keep your lines at about 72 characters. Long lines are hard to

One obvious solution is a table, possibly with wildcards if not all
combinations are different:

my @rules =
(
{
site       => 's1',
rank       => 'A'
experience => 'high',
ftptstat   => '*', # don't care
jobtype    => 'a',
level      => 1,
...
price      => 1288.
}
);

sub calculate_contract_price {
my (\$site, \$rank, \$experience, \$ftptstat, \$jobtype, \$level ... ) = @_;

for my \$rule (@rules) {
if ((\$rule-> eq '*' || \$site eq \$rule->) &&
(\$rule-> eq '*' || \$rank eq \$rule->) &&
(\$rule-> eq '*' || \$experience eq \$rule->) &&
...
) {
return \$hours * \$production * \$rule->;
}
}
}

Of course doing the same check on many variables implies that they
should be put into a common data structure, e.g. a hash:

sub calculate_contract_price {
my (\$param) = @_;

RULE: for my \$rule (@rules) {
for my \$p (keys \$param) {
next RULE unless (\$rule-> eq '*' || \$param-> eq \$rule->;
}
return \$hours * \$production * \$rule->;
}
}

(WARNING: Untested code)

Of course that table can also be stored in a database, which means that
a non-programmer could edit it.

hp

--
_  | Peter J. Holzer    | Fluch der elektronischen Textverarbeitung:
|_|_) |                    | Man feilt solange an seinen Text um, bis
| |   | hjp@hjp.at         | die Satzbestandteile des Satzes nicht mehr
__/   | http://www.hjp.at/ | zusammenpaĆt. -- Ralph Babel

## Re: approach to calculating pay

On Tuesday, August 27, 2013 2:48:58 PM UTC-4, Peter J. Holzer wrote:

Yes, I'll try.

One problem is that I have a flat algorithm for one kind of job (method) an
d a decision tree for another method of job, and I'm trying to integrate th
e approach. Another problem is that the data has a lot of errors, and I nee
d to be able to dynamically test the data. Running it through some kind of
cleaning up routine is more trouble than it's worth, since I just throw the
bad data away, i.e., the contract is trashed. Still another problem is tha
t some kinds of jobs have the metric built in, while others are a multiple
of some metric.

But ... you have given me an idea which might work. I'll build two hashes,
one for the piece work and the other for the flat rate, that might look lik
e below. I can then freeze the hash and load it every time I call it, or pe
rhaps put it into a flat file and reload the hash every time.

my (%pieces, %flatrate);

\$pieces = 672;
\$pieces = 1524;
\$pieces = 2286;
...
\$pieces = 927;
\$pieces = 1854;
\$pieces = 2781;

\$flatrate = 125;
\$flatrate = 100;
\$flatrate = 50;
\$flatrate = 200;
...

A big part of finding a solution to a problem is being able to articulate i
t to another person. I find that explaining it clearly so that another pers
on can understand the problem forces me to clarify it in my own mind, and s
ome times the solution is self evident.

I appreciate your help. I won't work on this until October, but I'll rememb
er to update this thread with the results.

CC.

## Re: approach to calculating pay

c> my (%pieces, %flatrate);

c> \$pieces = 672;
c> \$pieces = 1524;
c> \$pieces = 2286;

OOOOF!!

\$pieces = {
size1    => 672,
size2    => 1524,
size3    => 2286,
} ;

learn to remove redundancy. in the above case it is faster, easier to
write and much easier to read.

you can make a nested data tree for the keys in there as well. if it
gets too deep and complex, assign some of the lower nodes into scalars
and assign those into the parent tree. this is basic perl data
structures. you should never see lines with those dup hash lookups in
each one.

uri

## Re: approach to calculating pay

[...]

Hmm .... "don't make such mess of it next time"?. I think it is highly
unlikekly that you really need an orthognal 9D-space to classify the
type of contracts you have to deal with as this would either mean an
enormous amount of contracts or pretty much 'no classification at
all'. If you can express some of your input variables as functions of
some of the other input variables or omit them altogether, the problem
itself would become much simpler.

Apart from that, the 'hash idea' is generally sensible. A useful
simplication could be to create a 'compound key' from your input
values by joining them together with some 'neutral' character. Perl
has some builtin support for this (see description of \$; in 'perldoc
pervar') but I think creating real 'compound keys' would be a better
choice. The set of 'valid contracts' would then exist in a single
hash and the if - cascades would be replaced by joining the input
values and doing a lookup in this hash.