approach to calculating pay

Discussion in 'Perl Misc' started by ccc31807, Aug 27, 2013.

  1. ccc31807

    ccc31807 Guest

    This isn't strictly Perl question, but I've implemented this in Perl, and will re-implement it in Perl.

    I have several contracts to build about five times a year. Among other provisions, the 'contract price' is one of the provisions. While some are negotiated (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 parameters, and it returns a discrete integer, the 'contract price.' Rather than describe it, there is some semi-pseudo code below. As you will note, it consists 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 terms
    my ($site, $rank, $experience, $ftptstat, $jobtype, $level ... ) = parse_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;
    }
    ccc31807, Aug 27, 2013
    #1
    1. Advertising

  2. On 2013-08-27 13:31, ccc31807 <> wrote:
    > This isn't strictly Perl question, but I've implemented this in Perl, and will re-implement it in Perl.
    >
    > I have several contracts to build about five times a year. Among other provisions, the 'contract price' is one of the provisions. While some are negotiated (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 parameters, and it returns a discrete integer, the 'contract price.' Rather than describe it, there is some semi-pseudo code below. As you will note, it consists of a large number (almost 100) of if-elsif statements.


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



    > 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 terms
    > my ($site, $rank, $experience, $ftptstat, $jobtype, $level ... ) = parse_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.
    > }


    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->{site} eq '*' || $site eq $rule->{site}) &&
    ($rule->{rank} eq '*' || $rank eq $rule->{rank}) &&
    ($rule->{experience} eq '*' || $experience eq $rule->{experience}) &&
    ...
    ) {
    return $hours * $production * $rule->{price};
    }
    }
    }

    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->{$p} eq '*' || $param->{$p} eq $rule->{$p};
    }
    return $hours * $production * $rule->{price};
    }
    }

    (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
    | | | | die Satzbestandteile des Satzes nicht mehr
    __/ | http://www.hjp.at/ | zusammenpaƟt. -- Ralph Babel
    Peter J. Holzer, Aug 27, 2013
    #2
    1. Advertising

  3. ccc31807

    ccc31807 Guest

    On Tuesday, August 27, 2013 2:48:58 PM UTC-4, Peter J. Holzer wrote:
    > Please keep your lines at about 72 characters. Long lines are hard to
    > read.


    Yes, I'll try.

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


    One problem is that I have a flat algorithm for one kind of job (method) and a decision tree for another method of job, and I'm trying to integrate the approach. Another problem is that the data has a lot of errors, and I need 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 thebad data away, i.e., the contract is trashed. Still another problem is that 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 like below. I can then freeze the hash and load it every time I call it, or perhaps put it into a flat file and reload the hash every time.

    my (%pieces, %flatrate);

    $pieces{level1}{experience1}{certification1}{size1} = 672;
    $pieces{level1}{experience1}{certification1}{size2} = 1524;
    $pieces{level1}{experience1}{certification1}{size3} = 2286;
    ....
    $pieces{level2}{experience2}{certification2}{size1} = 927;
    $pieces{level2}{experience2}{certification2}{size2} = 1854;
    $pieces{level2}{experience2}{certification2}{size3} = 2781;

    $flatrate{level1}{size1} = 125;
    $flatrate{level1}{size2} = 100;
    $flatrate{level1}{size3} = 50;
    $flatrate{level2}{size3} = 200;
    ....

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

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

    CC.
    ccc31807, Aug 27, 2013
    #3
  4. ccc31807

    Uri Guttman Guest

    >>>>> "c" == ccc31807 <> writes:

    c> my (%pieces, %flatrate);

    c> $pieces{level1}{experience1}{certification1}{size1} = 672;
    c> $pieces{level1}{experience1}{certification1}{size2} = 1524;
    c> $pieces{level1}{experience1}{certification1}{size3} = 2286;

    OOOOF!!

    $pieces{level1}{experience1}{certification1} = {
    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
    Uri Guttman, Aug 28, 2013
    #4
  5. ccc31807 <> writes:
    > This isn't strictly Perl question, but I've implemented this in Perl, and will re-implement it in Perl.
    >
    > I have several contracts to build about five times a year. Among other provisions, the 'contract price' is one of the provisions. While some are negotiated (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 parameters, and it returns a discrete integer, the 'contract price.' Rather than describe it, there is some semi-pseudo code below. As you will note, it consists 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 terms
    > my ($site, $rank, $experience, $ftptstat, $jobtype, $level ... ) = parse_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"; }
    > }


    [...]

    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.
    Rainer Weikusat, Aug 28, 2013
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jenny

    Willing to pay for help!

    Jenny, Nov 28, 2003, in forum: Perl
    Replies:
    2
    Views:
    455
    Jenny
    Nov 29, 2003
  2. Doris Cox
    Replies:
    0
    Views:
    534
    Doris Cox
    Dec 2, 2003
  3. Dennis
    Replies:
    0
    Views:
    681
    Dennis
    Dec 2, 2003
  4. Robert Johnson

    Need a few lines of code help, will pay!

    Robert Johnson, Aug 3, 2003, in forum: ASP .Net
    Replies:
    3
    Views:
    314
    makthar
    Aug 4, 2003
  5. umberto
    Replies:
    0
    Views:
    397
    umberto
    Nov 18, 2003
Loading...

Share This Page