in reply to Optimizing a double loop
My solution is based on the idea of a step function, often spelled "µ" in math, and adding them together (function of x, edge at t):
µ(x, t) = 0 if x < t
= 1 if x > t
= ?? if x == t (often 1/2 in continuous math functions)
As this is about discrete values, I'd rather make that
µ(x, t) = 0 if x < t
= 1 if x > t
= 1 if x == t (for discrete input)
That way, the added value for a range, say [20, 50], can be
µ(x, 20) - µ(x, 51)
So, just as with moritz's solution, you can store the value for a range as 2 tuples for each edge:
You can imagine this to represent a number of Dirac pulses; the combination of step functions is the integral of this set of pulses, or, because we're in the discrete case, the sum of amplitudes of every pulse on its left.%step = ( 20 => 1, 50+1 => -1 );
For each range you add, in the same hash, you can then increment the value for the lower edge, and decrement for the upper edge + 1.
Now, the next step is to convert this data structure to the final outcome. If you need a complete data structure for the whole spectrum, you'll have to loop through the full range once, on each edge, adding the value for $step{$edge} to the previous accumulated value and assigning that to the range:my %step; foreach(@range) { $step{ $_->[0] }++; $step{ $_->[1]+1 }--; }
Tested withmy @edge = sort { $a <=> $b } keys %step; my $step = 0; my $x = shift @edge; for(my $i = $x; defined $x; $i++) { if($i == $x) { $step += $step{$x}; $x = shift @edge; } $arr[$i] += $step; }
The end result of print "@arr\n"; is:@arr = (0) x 120; @range = ([20, 50], [30, 100]);
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|---|