in reply to Scoping problems in nested loops

length(@{$matches{$element}{$site}} looks rather surprising to me. Consider:

my @array = ('bannana', 'apple', 'orange'); print length (@array);

Prints '1'. Most likely what you really wanted was the number of elements in the array. That is simple @array in a scalar context. However is seems like you really want to iterate over the array so a beter construct would be:

for my $low (@{$matches{$element}{$site}}) {

and omit the following line initialising $low. There are a number of places where the same thing seems to have been done.

Other changes I'd make involve early exits from loops rather than nesting inside if statements, removing duplicated code, removing superfluious nexts, using Perl for loops rather than C for loops and adding a little vertical whitespace to make flow clearer. At the end of that process I get:

my @fastarray; my %matches; my %sets; my $span; for my $element (@fastarray) { my $setscounter = 0; next unless defined %{$matches{$element}}; for my $site (sort {$a <=> $b } keys %{$matches{$element}}) { next unless @{$matches{$element}{$site}}; for my $low (@{$matches{$element}{$site}}) { my $lowerlimit = $low + 0; my $upperlimit = $span + $lowerlimit; for my $sitekey (sort {$a <=> $b } keys %{$matches{$elemen +t}}) { next unless @{$matches{$element}{$sitekey}}; my @arrayA = (); for my $hElem (@{$matches{$element}{$sitekey}}) { print "...in \$hElem\n"; if ($hElem >= $lowerlimit && $hElem <= $upperlimit +) { push (@arrayA, $hElem); } } if (@arrayA) { $sets{$element}[$setscounter]{$sitekey} = \@arrayA +; print "\$sets{$element}[$setscounter] is:\n"; print Dumper(%{$sets{$element}[$setscounter]}); @arrayA = (); } else { $sets{$element}[$setscounter]{$sitekey} = undef; } } $setscounter++; } } }

which may or may not be nothing at all like what you intended ;).


DWIM is Perl's answer to Gödel

Replies are listed 'Best First'.
Re^2: Scoping problems in nested loops
by mdunnbass (Monk) on Nov 15, 2006 at 15:25 UTC
    Thanks. That looks really great.

    I've been playing with it, and I did hit one snag so far. The arrays sotred in @{$matches{$element}{$sitekey}} contain possibly millions of elements, all stored in numerical order. If we assume that the ones being pushed into @arrayA are going to number a dozen or less, it seems really wasteful to me to sift through the entire array, for instance, once you've already reached values >= $upperlimit.

    This is why I had included some of the early loop exits and so on. It will (presumaby) greatly increase the speed of the program, which is highly desirable. What are your thoughts on modifying your code here:

    for my $hElem (@{$matches{$element}{$sitekey}}) { print "...in \$hElem\n"; if ($hElem >= $lowerlimit && $hElem <= $upperlimit) { push (@arrayA, $hElem); } }
    To something along these lines instead? :

    for my $hElem (@{$matches{$element}{$sitekey}}) { next unless ($hElem >= $lowerlimit); break unless ($hElem <= $upperlimit); print "...in \$hElem\n" push (@arrayA, $hElem); }
    Thanks,
    Matt

      The loop with early exit looks fine. However if there are large numbers of elements and the range represents a small fraction of the total number of elements, then I'd be inclined to do a binary search for the two end elements in the range and use an array slice to copy the elements in the range out. You may find Binary search helps as a starting point for the search code.

      Given two end element indexes the following does the slice and copy:

      @arrayA = @{$matches{$element}{$sitekey}}[$first .. $last];

      DWIM is Perl's answer to Gödel
        OK, I think I see where you're going with that but....

        I don't have the indices of the array elements, I would just have the values. And I am under the impression that slicing only works when you have the indices, not the values. Besides, if I am looking for any $x where
        $x <= $upperlimit && $x >= $lowerlimit
        I don't actually know that $upperlimit corresponds to a value in the array.

        So, I'm not sure that that accomplishes what you think it does.

        Also, as for my early exits, I realized break was the wrong command, and last seems to be doing the trick I wanted..

        Thanks,
        Matt