Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Process order

by anniyan (Monk)
on Jun 09, 2006 at 11:14 UTC ( #554469=perlquestion: print w/replies, xml ) Need Help??
anniyan has asked for the wisdom of the Perl Monks concerning the following question:

Monks i have hash in which i have 'Process' as key and 'Order' as value.

Key Value PR1 2 PR2 4 PR3 1 PR4 3

I want to do the processing of subroutines according to the precedence order given in the hash. For example in the above hash the 'PR3' should be executed first and 'PR1' second and so on. So in the following code, third subroutine should be processed first and first subroutine should be processed second and so on without changing the subroutine name. How to achieve this?

$input = &process1 ($input) $input = &process2 ($input) $input = &process3 ($input) $input = &process4 ($input)

I can achieve this by using the subroutine name as a key in the above hash and can call the subroutines after sorting as shown below. But i want the process name as shown above like '&process1'... and should not be changed to '&PR1'.... as i have tried below.

The way i tried one way (here i have changed subroutine name as per th +e key in the hash, which i don't want): for (sort keys %po) { $input = &$_ ($input); }

I think that is not the correct way. Is there any module or any other way to do this? I can also achieve by writing combination of four subroutines with different orders but i know that is not correct method.

The second way i tried but not correct (just i gave a try): for (keys %po) { $input = &process1 ($input) if (po{$_} == 1); $input = &process2 ($input) if (po{$_} == 2); $input = &process3 ($input) if (po{$_} == 3); $input = &process4 ($input) if (po{$_} == 4); }


Replies are listed 'Best First'.
Re: Process order
by Zaxo (Archbishop) on Jun 09, 2006 at 11:19 UTC

    You can sort the keys by value,

    my @sorted = sort {$po{$a} <=> $po{$b}} keys %po;
    You would do better associating a name to coderef through a hash, an arrangement usually called a dispatch table. What you're trying is calling through symbolic references.

    (Added) With your calling pattern of calling on and modifying $input, you might consider writing your subs to modify their argument.

    my %process = ( PR1 => sub { $_[0] = process1($_[0]) }, PR2 => sub { $_[0] = process2($_[0]) }, # . . . ); my %po = ( PR1 => 4, PR2 => 2, PR3 => 1, PR4 => 3, PR5 => 5, ); for (sort {$po{$a} <=> $po{$b}} keys %po) { $process{$_}($input); }
    It would be best if you made sure all the keys of %po existed in $process. How are you deciding priority? That could have a huge influence on how you actually do this.

    After Compline,

      Zaxo thanks for your prompt reply.

      I don't want to change the subroutine names (process1, process2..). The keys in the above hash (process names) are got from another input file. They are CODE which i cant change.


        Look again. PR1 calls process1, PR2 calls process2, etc. Nothing was renamed.

        Update: Oops, it seems the code wasn't originally there.

Re: Process order
by davorg (Chancellor) on Jun 09, 2006 at 11:50 UTC

    You have a number of subroutines that you want to execute in a certain order. To me, that indicates that what you actually want is an array of subroutine references (order should always make you think of arrays). So the problem becomes, how to convert the hash you have into a more useful array.

    The first thing to set up is a hash that maps the symbolic names that you have to actual subroutine references. That looks something like this:

    my %subs = ( PR1 = \&process1, PR2 = \&process2, PR3 = \&process3, PR4 = \&process4, );

    Next, we need to convert your hash into an array, using code something like this:

    my @processes; foreach (sort { $po{$a} <=> $po{b} } keys %po) { push @processes, $_; }

    This puts your symbolic code (PR1, PR2, etc) into the array, but we can change that to put the subroutine reference there instead.

    foreach (sort { $po{$a} <=> $po{b} } keys %po) { push @processes, $subs{$_}; }

    Lastly, you can interate across the array, calling all of your subroutines.

    foreach (@processes) { $input = $_->($input); }

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Process order
by dsheroh (Prior) on Jun 09, 2006 at 15:17 UTC
    If all priorities are unique, the sorting can be done very simply with reverse:
    #!/usr/bin/perl -w use strict; my %input = ( PR1 => 2, PR2 => 4, PR3 => 1, PR4 => 3, ); my %by_priority = reverse %input; foreach (sort keys %by_priority) { print $by_priority{$_}, "\n"; }
    Which gives:
    $ ./ PR3 PR1 PR4 PR2
    After sorting, I would use a hash of code references (as in davorg's reply) to execute the actual processes.
Re: Process order
by kwaping (Priest) on Jun 09, 2006 at 14:41 UTC
    How's this?
    #!/usr/bin/perl use strict; use warnings; my $input = 'a'; my %po = ( PR1 => 2, PR2 => 4, PR3 => 1, PR4 => 3, ); foreach my $key (sort { $po{$a} <=> $po{$b} } keys %po) { $key =~ s/^PR/process/; $input = eval "$key(\$input)" or die $@; print $input . $/; # debugging output } sub process1 { lc(shift) . 1 } sub process2 { lc(shift) . 2 } sub process3 { uc(shift) . 3 } sub process4 { uc(shift) . 4 }

    A3 a31 A314 a3142

    Update: eval can be dangerous! Use this solution only if you are sure that the value of $input is safe! Taint mode highly recommended.

    It's all fine and dandy until someone has to look at the code.

      $input = eval "$key(\$input)" or die $@;
      can be replaced with the safer
      $input = do { no strict 'refs'; &{$key}($input) };
      A dispatch table would be even safer.

      Zaxo, davorg and kwaping thanks for your wonderful replies and i sorted out my problem by the ideas given by you monks.

      ikegami, Zaxo added the coding part after i posted the reply. :-)


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://554469]
Approved by Corion
[karlgoethebier]: ames28909: http://eu.wiley. com/WileyCDA/ WileyTitle/ productCd- 0471986151.html totally outdated ;-)

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (11)
As of 2017-05-25 16:27 GMT
Find Nodes?
    Voting Booth?