Date: Sun, 1 Jul 2001 02:02:49 -0500
From: "Rich" <bigrich318@yahoo.com>
Subject: Re: inline average
Message-Id: <tjtiq6kf3tmh89@corp.supernews.com>


"David Frauzel" <nogard@gnosrehtaew.ten> wrote in message
news:9hm1cs$2h15$1@news.aros.net...
> This is perhaps esoteric, but I'm curious.
>
> Let's say I have the hash:
>
> %values = (
>   "red" => 5.0,
>   "orange" => 4.0,
>   "yellow" => 5.5,
>   ...
> )
>
> I'd like to have a final element in the hash, "average", which always
points
> to the average of all of the other elements - something like an inline
> function. I'm thinking it would look like this:
>
> $values{"average"} = {
>   my $total = 0;
>   foreach $color (@spectrum) {
>     $total += $values{$color};
>   }
>   $total = $total / ($#spectrum + 1);
>   return $total;
> }
>
> (The above is obviously not real perl, it's just for the sake of
> illustration.)

You were on the right track. You want to use an anonymous subroutine.

#!/usr/bin/perl -w

use strict;

my %values = (
  red => 5.0,
  orange => 4.0,
  yellow => 5.5,
  average => "",
);

  $values{average} = &{sub {
  my $total = 0;
  my $colors = 0; #number of valid color values to average
  foreach my $color (keys %values) {
    if ($color ne "average"
        &&
        # Don't use value of  $values{$color} unless it's a number
        $values{$color} =~ /^-?(?:(?:\d+\.?\d*)|(?:\d*\.\d+))$/) {
            $total += $values{$color};
            $colors++;
    }
  }
  return sprintf("%.2f", $total /= $colors);
}};

print "The average is $values{average}";

__END__

sub { ..code..} produces a  reference. Wrapping it in &{ } de-references the
value before assigning it to $values{average}

I didn't spend a lot of time on the example, you can adjust it to suit your
needs. If you are certain that all colors will have a valid numeric value,
you could eliminate the check.


Keep checking back, I'm certain their will be many posts to follow that will
provide micro-efficiency corrections as well as many different ways to get
the same results.



Rich




