http://qs321.pair.com?node_id=929863


in reply to Tracking minimum of values in an array over time

Create a counter, at increment time check to see if the incremented value == the minimum value, when counter == @a start processing. This should work if you are updating through a single sub and if the minimum is constant. (if you need to be able to regenerate for some reason iterate once to set the count)

                - Ant
                - Some of my best work - (1 2 3)

Replies are listed 'Best First'.
Re^2: Tracking minimum of values in an array over time
by liverpole (Monsignor) on Oct 05, 2011 at 19:36 UTC
    What ++suaveant said.

    I wrote the program below to illustrate how you might do this. Note that you increment your "check" variable (in my program it's called $nfloor) only when an element becomes exactly the "floor" value. You can change the value of $b_slow to zero to make it call the subroutine fast() instead of slow(), and play with the values of $array_size and $floor to see how they affect the overall program speed. ($b_debug, if set, prints out the array each time; you probably only want to do this if $array_size and $floor are both quite small!):

    #!/usr/bin/perl -w # Libraries use strict; use warnings; use 5.010; # User-defined my $b_slow = 1; my $array_size = 3000; my $floor = 50; my @array = ( 0 ) x $array_size; my $b_debug = 0; # Main program my $start = time(); while (1) { # Pick a random index, and increment the corrsponding value my $idx = int(rand(@array)); # Check all values to see if they've reached $floor my $b_reached = $b_slow? slow(\@array, $idx): fast(\@array, $idx); $b_debug and print "@array\n"; $b_reached and last; } my $nsecs = time() - $start; print "Reached floor '$floor' in $nsecs second(s)\n"; # Subroutines sub slow { my ($a_array, $idx) = @_; ++$array[$idx]; for (my $i = 0; $i < @$a_array; $i++) { my $val = $a_array->[$i]; ($val < $floor) and return 0; } return 1; } sub fast { my ($a_array, $idx) = @_; state $nfloor = 0; my $val = ++$a_array->[$idx]; if ($floor == $val) { ++$nfloor; } return ($nfloor < $array_size)? 0: 1; }

    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

      Now that's a fantastic idea. Instead of trying to track the minimum of the set, track how many in the set have passed my floor value.

      My increment value will usually be more than one, so I'll have to verify that the increment did result in crossing the floor, but that's easy enough.

      Great idea from both of you, many thanks!

      liverpole,
      I haven't read your code but in thinking about the problem, you should never need to scan the array. The following is completely untested but it explains why I believe it is unnecessary.
      my @array = ((0) x 100); my $inc_array = gen_min_tracker(0, 100, \@array); my $floor = 27; my $new_min = inc_array(42, 7); # increment the 43rd element by 7 if ($new_min >= $floor) { print "The floor has been reached\n"; } sub gen_min_tracker { my ($curr_min, $curr_cnt, $aref) = @_; my ($next_min, $next_cnt); return sub { my ($idx, $inc) = @_; my $val = $aref->[$idx]; my $add = $val + $inc; if ($val == $curr_min) { $curr_cnt--; if (! defined $next_min || $add <= $next_min) { $next_min = $add; $next_cnt++; } if (! $curr_cnt) { ($curr_val, $curr_cnt, $next_val, $next_cnt) = ($next_ +val, $next_cnt, undef, undef); } } $aref->[$idx] += $inc; # let's not forget to actually increme +nt return $curr_min; }; }
      Update: Due to some unknown copy/paste error, the code above has been altered slightly from its original form to hopefully be correct despite still not being tested.

      Warning: In the CB, ambrus points out that this approach is flawed. It is not safe to reset $next_val and $next_cnt to undef. The assumption was that anytime one of the $curr_min values was incremented, it would be incremented to the $next_min and that no other value in the array could possibly be smaller. The solution is simple - put in the O(N) low water mark algorithm keeping track of the min value and count.

      Consideration: While you can't keep track of the minimum value without periodically scanning, you can still achieve the OP's goal as suaveant points out.

      Cheers - L~R

        The array scan was in there to allow comparison of "slow" vs "fast" I believe.

                        - Ant
                        - Some of my best work - (1 2 3)