use List::Utils qw(reduce); my %hits = map { $_ => [0], } (qw(google msn spam)); my $start = time; my $max_queue_size = 60; # our window is 60 seconds while (defined my $line = <$log>) { # process log my $who = get_hit($line); if ($who) { my $now = time; my $bucket = $max_queue_size - $now-$start; # Keep our queue at the appropriate length my $queue_length = @{ $hits{ $who }}; if ($queue_length > $max_queue_size) { splice @{ $hits{ $who }}, 0, $queue_length - $max_queue_size; }; $hits{ $who }->[$bucket]++; # count a hit }; # Aggregate the buckets using reduce() # respectively update the aggregates by adding the first item # and subtracting the item that just fell out of the reporting window };