Paul Lutus 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:emptysetfuncs\)
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
$ 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.
···
ara.t.howard@noaa.gov wrote:
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407