Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

my %fpc = ( R0 => { fpc1 => 5, fpc2 => 4, }, R2 => { fpc1 => 3, fpc2 => 2, }, R3 => { fpc1 => 1, fpc2 => 0, }, ); my %pic = ( R0 => { pic1 => 5, pic2 => 4, }, R2 => { pic1 => 3, pic2 => 2, }, R3 => { pic1 => 1, pic2 => 0, }, ); @router = ( "R0", "R2", "R3" ); for my $rh (@routers) { my $r = shift(@router); print "value of r is $r\n"; OUTER: for my $f (values %{ $fpc{$r} }) { INNER: for my $p (values %{ $pic{$r} }) { print "request chassis pic offline fpc-slot $f pic-slot $p +\n"; next OUTER; } } }

Output is

value of r is R0

request chassis pic offline fpc-slot 5 pic-slot 4

request chassis pic offline fpc-slot 4 pic-slot 4

I thought it will take first value of $pic{R0}, which is 5 but it is taking $pic{R0} second value. Also, is there a way to increment the second "for" loop also. In the second output, "request chassis pic offline fpc-slot 4 pic-slot 4", it is taking the correct values for fpc, but pic it is still retaining the old value 4. Is there a way to solve it?

Replies are listed 'Best First'.
Re: NEXT statement in for loop
by Corion (Patriarch) on Jun 05, 2016 at 16:26 UTC

    Please post code that actually works. Your code seems to be a snippet from a larger program, at least there is mention of @router and @routers, but only @router gets initialized.

    It's hard what you actually expect as output - maybe you can rephrase your problem statement?

    You seem to think that hashes or values %hash are ordered, but they are not. Maybe that is your problem?

      pasting the code again

      my @routers =$r[0]; my @router = ( "R0", "R2", "R3" ); my %fpc = ( R0 => { fpc1 => 5, fpc2 => 4, }, R2 => { fpc1 => 3, fpc2 => 2, }, R3 => { fpc1 => 1, fpc2 => 0, }, ); my %pic = ( R0 => { pic1 => 5, pic2 => 4, }, R2 => { pic1 => 3, pic2 => 2, }, R3 => { pic1 => 1, pic2 => 0, }, ); @router = ( "R0", "R2", "R3" ); for my $rh (@routers) { my $r = shift(@router); print "value of r is $r\n"; OUTER: for my $f (values %{ $fpc{$r} }) { INNER: for my $p (values %{ $pic{$r} }) { print "request chassis pic offline fpc-slot $f pic-slot $p +\n"; next OUTER; } } }

      Yes, values in hash are not ordered as expected

        I'm not clear whether your question has been answered yet. To further clarify your code, I've reindented it and added some more diagnostics that show the order that values will take for a given hash:

        #!perl -w use strict; use Data::Dumper; my @r = ('R0'); my @routers =$r[0]; my @router = ( "R0", "R2", "R3" ); my %fpc = ( R0 => { fpc1 => 5, fpc2 => 4, }, R2 => { fpc1 => 3, fpc2 => 2, }, R3 => { fpc1 => 1, fpc2 => 0, }, ); my %pic = ( R0 => { pic1 => 5, pic2 => 4, }, R2 => { pic1 => 3, pic2 => 2, }, R3 => { pic1 => 1, pic2 => 0, }, ); @router = ( "R0", "R2", "R3" ); for my $rh (@routers) { my $r = shift(@router); print "value of r is $r\n"; print "Processing routers in order " . join(",", values %{ $fp +c{$r} }), "\n"; OUTER: for my $f (values %{ $fpc{$r} }) { print "Processing pic-elements for $r in order " . join( " +,", values %{ $pic{$r} }), "\n"; INNER: for my $p (values %{ $pic{$r} }) { print "request chassis pic offline fpc-slot $f pic-slo +t $p\n"; next OUTER; } } }

        Note that between runs of the program, the order can change for every hash. The best way to work with this is to save the order you want in a separate list:

        c:\Users\Corion\Projekte>perl -w tmp.pl value of r is R0 Processing routers in order 5,4 Processing pic-elements for R0 in order 5,4 request chassis pic offline fpc-slot 5 pic-slot 5 Processing pic-elements for R0 in order 5,4 request chassis pic offline fpc-slot 4 pic-slot 5 c:\Users\Corion\Projekte>perl -w tmp.pl value of r is R0 Processing routers in order 5,4 Processing pic-elements for R0 in order 4,5 request chassis pic offline fpc-slot 5 pic-slot 4 Processing pic-elements for R0 in order 4,5 request chassis pic offline fpc-slot 4 pic-slot 4 c:\Users\Corion\Projekte>perl -w tmp.pl value of r is R0 Processing routers in order 5,4 Processing pic-elements for R0 in order 4,5 request chassis pic offline fpc-slot 5 pic-slot 4 Processing pic-elements for R0 in order 4,5 request chassis pic offline fpc-slot 4 pic-slot 4 c:\Users\Corion\Projekte>perl -w tmp.pl value of r is R0 Processing routers in order 5,4 Processing pic-elements for R0 in order 5,4 request chassis pic offline fpc-slot 5 pic-slot 5 Processing pic-elements for R0 in order 5,4 request chassis pic offline fpc-slot 4 pic-slot 5

        In your case, I would save the list of numbers like the following:

        my @items = values ${ $fpc{$r} }; for my $f (@values) { ... }

        If the order of the values is important and the keys not then maybe use a hash of arrays (HoA)

        #!perl use strict; my @routers = ( "R0", "R2", "R3" ); my %fpc = ( R0 => [5,4], R2 => [3,2], R3 => [1,0], ); my %pic = ( R0 => [5,4], R2 => [3,2], R3 => [1,0], ); for my $r (@routers) { print "value of r is $r\n"; for my $f (@{ $fpc{$r} }) { for my $p (@{ $pic{$r} }) { print "request chassis pic offline fpc-slot $f pic-slot $p\n"; } } }
        poj
Re: NEXT statement in for loop
by Laurent_R (Canon) on Jun 05, 2016 at 19:01 UTC
    Since you don't define @routers and don't use the $rh loop variable, it would seem that this:
    for my $rh (@routers) { my $r = shift(@router); # ...
    could probably be rewritten more clearly this way:
    for my $r (@router) { # ...
    But it depends on whether you plan to use the @router somewhere else in your code.

    Update: s/;/{/;. Thanks to Athanasius for pointing out a copy/paste error.

Re: NEXT statement in for loop
by Athanasius (Archbishop) on Jun 06, 2016 at 04:26 UTC

    As the title of this thread is “NEXT statement in for loop,” it may be as well to look at the three nested for loops in the OP and examine their structure. Adopting Laurent_R’s simplification, we get:

    for my $r (@router) { print "value of r is $r\n"; OUTER: for my $f (values %{ $fpc{$r} }) { INNER: for my $p (values %{ $pic{$r} }) { print "request chassis pic offline fpc-slot $f pic-slot $p +\n"; next OUTER; } } }

    The effect of the next statement is to terminate the INNER loop after its first iteration; so the code can be written equivalently with just two loops:

    for my $r (@router) { print "value of r is $r\n"; OUTER: for my $f (values %{ $fpc{$r} }) { my $p = (values %{ $pic{$r} })[0]; print "request chassis pic offline fpc-slot $f pic-slot $p\n"; } }

    See next and Loop Control.

    As others have noted, hashes are unordered, so the list returned by values %{ $fpc{$r} } will vary across successive runs of the script. If an ordered hash is required, has various options; for example, Hash::Ordered — and note the “SEE ALSO” section in that module’s documentation.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: NEXT statement in for loop
by Anonymous Monk on Jun 05, 2016 at 17:57 UTC
    I thought it will take first value of $pic{R0}, which is 5 but it is taking $pic{R0} second value.

    To emphasize something that Corion pointed out in his answer: Hashes are unordered. There is no "first" or "second" value. If you need things in order, you should probably put them in an array, not a hash.

    my %pic = ( R0 => [ 5, 4 ], R2 => [ 3, 2 ] );

      But, you can't define array in hash, right ?. I don't think this will work

      my %pic = ( R0 => [ 5, 4 ], R2 => [ 3, 2 ] );