Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Nested Loops vs Good programming

by Sporti69 (Acolyte)
on Nov 14, 2008 at 11:20 UTC ( #723626=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks,

I have been working on a script that parses XML using the XML::Simple module. I am now in a phase where I want to make my code more dynamic. (it's already quite dynamic, but not in nesting eg more xml sub sub sub sub sub elements.)

I have quite some nested loops that all need values from upper loops. Now I wonder if it is possible to make this script more universal with XML::Simple

As you will see I speak to the top XML element and start 'for' looping everything. Then I use for $i loops every time again. Just look at the code and you will see that $sub1 $sub2 $sub3 and $sub4 are the same

Is there a way to program more effecient when you need those loops for building references?

#!/usr/bin/perl -- use strict; use warnings; use Cwd; use Win32::OLE; use XML::Simple; my $dir = cwd(); opendir(DIR, "."); my @file = grep(/\.xml$/,readdir(DIR)); closedir(DIR); use Data::Dumper; local $Data::Dumper::Indent=1; #print Dumper($doc); my $xs1 = XML::Simple->new(); my $doc = $xs1->XMLin($file[0], keyattr=>[], ForceContent=>1, ForceArr +ay=>1); for my $sub1 ( sort keys %{ $doc } ){ unless (ref($doc->{$sub1})) { print "$doc->{$sub1} is not a reference at + all.\n"; next; } my $count = @{ $doc->{$sub1} }; print "\n$sub1\t"; for (my $i=0; $i <= $count; $i++) { for my $sub2 ( sort keys %{ $doc->{$sub1}[$i] } ){ unless (ref($doc->{$sub1}[$i]{$sub2})) { print "$doc->{$sub1}[$i]{$sub2} is not a r +eference at all.\n"; next; } my $count2 = @{$doc->{$sub1}[$i]{$sub2}}; for (my $j=0; $j <= $count2; $j++) { for my $sub3 ( sort keys %{ $doc->{$sub1}[$i]{$sub2}[$ +j] } ){ unless (ref($doc->{$sub1}[$i]{$sub2}[$j]{$ +sub3})) { print "$doc->{$sub1}[$i]{$sub2}[$j]{$sub3} + is not a reference at all.\n"; next; } my $count3 = @{$doc->{$sub1}[$i]{$sub2}[$j]{$sub3} +}; print "\n\t$sub2\t$sub3($count3)"; for (my $k=0; $k <= $count3; $k++) { print "\n"; for my $sub4 ( sort keys %{ $doc->{$sub1}[$i]{ +$sub2}[$j]{$sub3}[$k] } ){ print "\n\t\t\t$sub4 : "; print $doc->{$sub1}[$i]{$ +sub2}[$j]{$sub3}[$k]{$sub4}; } } } } } } }
And the XML for the ones who like to run it:
<A type="not_a_reference"> <B type="not_a_reference"> <C types="not_a_reference"> <element type="k" name="p" online="yes"/> <element type="i" name="e" online="yes"/> </C> <D jammer="not_a_reference"> <element type="kd" name="pd" online="no"/> <element type="id" name="ed" online="yes"/> <element type="yd" name="zd" online="no"/> </D> </B> <Z type="klote" zever="not_a_reference"> <C> <element type="k" name="z" online="yes"/> <element type="t" name="p" online="yes"/> </C> <E type="not_a_reference"> <element type="kd" name="pd" online="no" zever="inpakstkes +"/> <element type="id" name="ed" online="yes"/> </E> </Z> </A>

Replies are listed 'Best First'.
Re: Nested Loops vs Good programming
by snopal (Pilgrim) on Nov 14, 2008 at 14:09 UTC

    Recursion is your friend. By understanding both scoped variables and how to package and pass your current values forward in the recursive call, you can have both your current virtually unlimited level, and all previously detected superior values at any moment in time.

    Be aware that recursion is memory intensive, so this ability gives you extreme flexibility, at several costs. First, it becomes a memory hog for depth-wise structures which may leave you "out of memory". Second, you still have the reponsibility to eventually leave the recursion in an orderly fashion (usually by return at the end of each level).

    It is not good practice to step out of recursion before unwrapping all the depth you have accumulated. It is better to pass out your constructed structure or build an external structure if you need values outside the recursion.

Re: Nested Loops vs Good programming
by jwkrahn (Monsignor) on Nov 14, 2008 at 13:08 UTC

    I don't know about your stated problem, but your loops have an off-by-one error:

    my $count = @{ $doc->{$sub1} }; print "\n$sub1\t"; for (my $i=0; $i <= $count; $i++) {

    Should be:

    my $count = $#{ $doc->{$sub1} }; print "\n$sub1\t"; for my $i ( 0 .. $count ) {

    The same applies to $count2 and $count3.

      $count is a misnomer in your new code. If you change what a variable contains, you need to change its name too.

      Minimal fix (<=<):

      my $count = @{ $doc->{$sub1} }; for (my $i=0; $i<$count; $i++)

      Easier to read:

      my $count = @{ $doc->{$sub1} }; for my $i ( 0 .. $count-1 )


      my $last = $#{ $doc->{$sub1} }; for my $i ( 0 .. $last )
Re: Nested Loops vs Good programming
by graff (Chancellor) on Nov 14, 2008 at 17:48 UTC
    You said:
    I have quite some nested loops that all need values from upper loops.

    But in your code snippet, it seems like the only need you have for the values from upper loops is to use the hash keys and array index counters for navigating through the "doc" structure returned by XML::Simple.

    If that is also the situation for your "actual" application, then the suggestion about about using recursion will make that a moot point: your recursive sub simply takes as a parameter the hash ref -- on the initial (outermost) call, this is the hash ref returned by XML::Simple::XMLin. On subsequent (recursing) calls, it's a hash ref at successively lower levels of the structure.

    OTOH, if there are tag attributes at level 1, and you want to associate those with information that gets parsed at level 4 or whatever, you'll probably want your recursive sub to take additional parameters, so that info gleaned from an upper level can be passed to lower levels.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://723626]
Approved by jettero
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (7)
As of 2020-11-23 20:26 GMT
Find Nodes?
    Voting Booth?

    No recent polls found