[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[OT] calculations on lists of numbers

Ara.T.Howard

12/2/2006 4:03:00 AM

36 Answers

Christopher Schneider

12/2/2006 4:18:00 AM

0

I wonder if something like bc could do something along those lines.
The biggest problem is that you have to assume a lot of information
about the format of the list.

When you get something implemented, I'd be interested in seeing it.

-Chris

On Dec 1, 2006, at 9:02 PM, ara.t.howard@noaa.gov wrote:

>
> for years i've felt that i should be able to pipe numerical output
> into some
> unix command like so
>
> cat list | mean
> cat list | sum
> cat list | minmax
>
> etc.
>
> and have never found one. right now i'm building a ruby version -
> before i
> continue, does anyone know a standard unix or ruby version of this?
>
> cheers.
>
> -a
> --
> if you want others to be happy, practice compassion.
> if you want to be happy, practice compassion. -- the dalai lama


matthew.moss.coder

12/2/2006 4:25:00 AM

0

> cat list | mean

cat list | awk '{ s += $1; n += 1 } END { print s / n }'

> cat list | sum

cat list | awk '{ s += $1 } END { print s }'

> cat list | minmax

Hmmm..... need to study some more awk.

matthew.moss.coder

12/2/2006 4:27:00 AM

0

Oh... my samples assume each number is on its own line... dunno
offhand how to support an arbitrary amount of numbers on a line....

Ara.T.Howard

12/2/2006 5:01:00 AM

0

Ara.T.Howard

12/2/2006 5:02:00 AM

0

Paul Lutus

12/2/2006 5:33:00 AM

0

ara.t.howard@noaa.gov wrote:

>
> for years i've felt that i should be able to pipe numerical output into
> some unix command like so
>
> cat list | mean
> cat list | sum
> cat list | minmax
>
> etc.
>
> and have never found one. right now i'm building a ruby version - before
> i continue, does anyone know a standard unix or ruby version of this?

It is so easy to create in Ruby, a matter of minutes, that it is not
terribly important to do the search you are suggesting.

--------------------------------

#!/usr/bin/ruby -w

array = []

STDIN.read.split(/\s+/).each do |item|
if(v = item.to_f)
array << v
end
end

if(array.size > 0)
sum = 0
array.each { |v| sum += v }
mean = sum / array.size
puts sum.to_s + " " +
mean.to_s + " " +
array.min.to_s + " " +
array.max.to_s
end

--------------------------------

$ echo 1 2 3 4 5 | (script_name)

Output: 15.0 3.0 1.0 5.0

--
Paul Lutus
http://www.ara...

Joel VanderWerf

12/2/2006 8:28:00 AM

0

Paul Lutus wrote:
> ara.t.howard@noaa.gov wrote:
>
>> for years i've felt that i should be able to pipe numerical output into
>> some unix command like so
>>
>> cat list | mean
>> cat list | sum
>> cat list | minmax
>>
>> etc.
>>
>> and have never found one. right now i'm building a ruby version - before
>> i continue, does anyone know a standard unix or ruby version of this?
>
> It is so easy to create in Ruby, a matter of minutes, that it is not
> terribly important to do the search you are suggesting.

Disagree. I would like to know if a unix version exists, since it will
certainly be faster than ruby, run in less memory, and probably exist in
environments where ruby doesn't. So I think the search is worth while.

Also, it _is_ terribly important to scrutinize code one finds in a
newsgroup, so here we go...

> #!/usr/bin/ruby -w
>
> array = []
>
> STDIN.read.split(/\s+/).each do |item|
> if(v = item.to_f)
> array << v
> end
> end

- Use $stdin instead of STDIN, to play well with reassignment of $stdin,
in case this snippet ever becomes part of a library, and someone wants
to capture output.

- The code above can be simplified and improved so that files can be
named on the command line:

array = ARGF.read.split.map {|s| Float(s)}

(Is #Float better than #to_f? It depends. If you want "3foobar" to be
treated as 3.0 and you want "foobar3" to be treated as 0.0, stick with
#to_f (and keep the nil values out of the array). If you want the
program to die noisily on bad input, use #Float. As a bonus, you don't
have to deal with nil values.)

> if(array.size > 0)
> sum = 0
> array.each { |v| sum += v }
> mean = sum / array.size
> puts sum.to_s + " " +
> mean.to_s + " " +
> array.min.to_s + " " +
> array.max.to_s
> end

More idiomatically ruby, IMO, is the following:

unless array.empty?
sum = array.inject {|s,x| s+x}
mean = sum / array.size
puts "#{sum} #{mean} #{array.min} #{array.max}"
end

Also, you might want an empty array have a sum of 0, just so that the
nice algebraic properties hold:

[1, 2, 3, 4].sum + [].sum == [1, 2].sum + [3, 4].sum

(And, it's fairly standard:
http://wiki.r-project.org/rwiki/doku.php?id=tips:surprises:emp...)

That only makes sense for the

>> cat list | sum

invocation, of course.

Here's the implementation so far:

$ cat agr.rb
#!/usr/bin/env ruby

array = ARGF.read.split.map {|s| Float(s)}

sum = array.inject(0) {|s,x| s+x}

print sum
unless array.empty?
mean = sum / array.size
print " #{mean} #{array.min} #{array.max}"
end
puts

$ echo "1 2 3" | ./agr.rb
6.0 2.0 1.0 3.0
$ echo "1 2 3foo" | ./agr.rb
/agr.rb:3:in `Float': invalid value for Float(): "3foo" (ArgumentError)
from ./agr.rb:3
from ./agr.rb:3
$ echo "1 2 3" >data
$ ./agr.rb data data
12.0 2.0 1.0 3.0
[~/tmp] echo "" >empty_data
[~/tmp] ./agr.rb empty_data
0

>
> --------------------------------
>
> $ echo 1 2 3 4 5 | (script_name)
>
> Output: 15.0 3.0 1.0 5.0

And then what do you do if you are piping this output somewhere else?
Use cut to get the mean or whatever it was you wanted? The OP wanted
three separate functions. It might be better to use an argument to the
script to select which aggregate value is to be output.

There's not much point computing the min and max if only the mean was
requested.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Paul Lutus

12/2/2006 8:49:00 AM

0

Joel VanderWerf wrote:

> Paul Lutus wrote:
>> ara.t.howard@noaa.gov wrote:
>>
>>> for years i've felt that i should be able to pipe numerical output into
>>> some unix command like so
>>>
>>> cat list | mean
>>> cat list | sum
>>> cat list | minmax
>>>
>>> etc.
>>>
>>> and have never found one. right now i'm building a ruby version -
>>> before i continue, does anyone know a standard unix or ruby version of
>>> this?
>>
>> It is so easy to create in Ruby, a matter of minutes, that it is not
>> terribly important to do the search you are suggesting.
>
> Disagree.

It's a bit too late to disagree, in the face of the evidence that I said it,
then I did it.

> I would like to know if a unix version exists, since it will
> certainly be faster than ruby, run in less memory, and probably exist in
> environments where ruby doesn't. So I think the search is worth while.

Yes, all true, but that isn't what you disagreed with.

A number of *nix hands will probably put forth solutions that rely on awk or
bc (something I might have done in years past), and they will probably be
faster, and they certainly exist, and no need to write any Ruby code.

But writing something quick and serviceable in Ruby was extremely easy.

--
Paul Lutus
http://www.ara...

Paul Lutus

12/2/2006 9:30:00 AM

0

Joel VanderWerf wrote:

> puts "#{sum} #{mean} #{array.min} #{array.max}"

I'm not much into golf, but, since we've long since left the clubhouse, and
because I am very lazy:

puts [ sum,mean,array.min,array.max ].map { |v| v.to_s }.join(' ')

This has the sole advantage that particular elements can be added and
removed without a lot of typing. If no one expects to change the program,
then there's no point in it.

--
Paul Lutus
http://www.ara...

William James

12/2/2006 10:44:00 AM

0

ara.t.howard@noaa.gov wrote:
> for years i've felt that i should be able to pipe numerical output into some
> unix command like so
>
> cat list | mean
> cat list | sum
> cat list | minmax

Why drag in the cat when it's utterly superfluous?

mean <list
sum <list
minmax <list

>
> etc.
>
> and have never found one. right now i'm building a ruby version - before i
> continue, does anyone know a standard unix or ruby version of this?


Matthew Moss wrote:
> > cat list | mean
>
> cat list | awk '{ s += $1; n += 1 } END { print s / n }'

Reading a file isn't a magical ability; awk can do it.

awk "{s+=$0} END{print s/NR}" list

If there can be more than one number on a line:

awk "{for(i=1;i<=NF;i++)s+=$i; n+=NF} END{print s/n}" file

Ruby:

ruby -nale "BEGIN{$s=$n=0}; $s+=$F.inject(0){|x,y| x.to_f+y.to_f};
$n+=$F.size; END{puts $s/$n}" file

If there's memory enough for the whole file:

ruby -e "a=$<.read.split.map{|x|x.to_f};
puts a.inject{|x,y|x+y}/a.size" file