-5 .. -1 [ 1] # 0 .. 4 [ 7] ####### 5 .. 9 [ 6] ###### 10 .. 14 [ 7] ####### 15 .. 19 [ 3] ### 20 .. 24 [ 1] # #### sub show_histogram { # Prints a simple text histogram given a reference # to an array of integers. # Larry Leszczynski my ($array_ref, $binsize, $width) = @_; $binsize ||= 1; $width ||= 50; use POSIX qw(ceil floor); # Divide input data into bins: my %bin_count = (); # number of items in each bin foreach ( @$array_ref ) { my $bin = floor(($_+.5)/$binsize); $bin_count{$bin}++; } my $max_items = 0; # maximum items in a single bin foreach ( values %bin_count ) { $max_items = $_ if $_ > $max_items; } # Try to keep histogram on one page width: my $scale = 1; if ( $max_items > $width ) { if ( $max_items <= ($width*5) ) { $scale = 5; } else { while ( ($max_items/$scale) > $width ) { $scale *= 10; } } } my @bins = sort {$a <=> $b} keys %bin_count; my $bin = $bins[0]; # lowest value bin my $maxbin = $bins[-1]; # highest value bin my $binfmt_width = ( length $maxbin > length $bin ) ? length $maxbin : length $bin; my $cntfmt_width = length $max_items; my $start = $bin * $binsize; my $end = $start + $binsize - 1; do { my $count = $bin_count{$bin} || 0; my $extra = ( $count % $scale ) ? '.' : ''; printf "%*d .. %*d \[%*d\] %s$extra\n", $binfmt_width, $start, $binfmt_width, $end, $cntfmt_width, $count, '#' x ceil($count/$scale); $start += $binsize; $end += $binsize; } while ( $bin++ < $maxbin ); print "\n Scale: #=$scale\n" if $scale > 1; }