2008-09-06

class Array

A handful of methods that could be added to the class
Array
:
class Array

def sum
s=0
each{|e| s+=e}
s
end

def mul
m=1
each{|e| m*=e}
m
end

def mean
sum.to_f/length
end

def map_with_index
i=-1
map{|e| yield(e,i+=1)}
end

def map_with_index!
i=-1
map!{|e| yield(e,i+=1)}
end

def any_with_index?
each_with_index{|e,i| return true if yield(e,i)}
false
end

def all_with_index?
each_with_index{|e,i| return false unless yield(e,i)}
true
end

def find_index
each_with_index{|v,i| return i if yield(v)}
end

def find_indices
ret=[]
each_with_index{|v,i| ret<<i if yield(v)}
ret
end

def select_by_index(*indices)
ret=[]
indices.each{|ind| ret<<self[ind]}
ret
end

alias find_indexes find_indices

def to_hash
raise "Cannot convert to Hash!" unless all?\
{ |e|
e.respond_to? :length and e.length==2 and e.respond_to? :[]
}
h={}
each{|e| h[e[0]]=e[1]}
h
end

def keys_to_hash
h={}
each{|e| h[e]=yield(e)}
h
end

def keys_with_index_to_hash
h={}
each_with_index{|e,i| h[e]=yield(e,i)}
h
end

def with(a2)
ensure_same_length(a2)
map_with_index{|e,i| [e,a2[i]]}
end

def with_to_hash(a2)
ensure_same_length(a2)
h={}
each_with_index{|e,i| h[e]=a2[i]}
h
end

def count_all
h={}
each\
{ |e|
h[e]||=0
h[e]+=1
}
h
end

def group_by
h={}
each\
{ |e|
g=yield(e)
h[g]||=[]
h[g]<< e
}
h.map{|g,ee| ee}
end

alias contain? include?
alias has? include?

def rand
a=to_a
a[Kernel.rand(a.length)] unless a.empty?
end

private

def ensure_same_length(arg)
raise ArgumentError,"Argument must be of the same length!"\
unless arg.respond_to? :length and length==arg.length\
and arg.respond_to? :[]
end

end
They are not perfect, but I use them quite a lot.

Some of them (or similar methods) will be present in Ruby 1.9. For example there will be a method
inject
(or
reduce
) working like this:
[1,4,5].reduce(:*)           #=> 20 # 1*4*5
["a","b","dd"].reduce(:+) #=> "abdd"
As you see, they are better than my
sum
, because they work for any type for which the operation is defined. This reduce is not hard to implement, too, but it will probably work a bit faster when included in Ruby core.

Ruby 1.9 is also going to have
group_by
, working exactly like mine, as far as I know.

Move to Enumerable
One more enhancement that can be done in the above code is to move all the methods in the module
Enumerable
(just write
module Enumerable
instead of
class Array
at the top). It allows you to use these methods also with other enumerable types, like
Hash
. You'll have to test the methods, though, as not all of them make sense when used with structures where the elements are not ordered.

Add to load path
If you create some files that you'd like to be easily accessible in your Ruby programs, you can add the path to your files to Ruby load path, so that you will be able to
require
your files without giving the full path. Under Windows, just go to environment variables, and add
RUBYLIB = P:/ath/To/Your/Dir
The path will be automatically added to Ruby load path each time Ruby starts, which can be verified by typing
$:
(or
$LOAD_PATH
) in irb and looking for your path.

If you want some of your files to be loaded even without the need to
require
them, then you can add them to the environment variable RUBYOPT. This variable can already contain -rubygems. If you want the file P:/ath/To/Your/Dir/start.rb to be loaded at startup, change the variable to
-rubygems -rstart
Each word starting with -r makes ruby load a file named by the rest of the word. Ruby will find your file because you already added file path to Ruby load path. If you want to load more files at startup, it is best to
require
them from within your first file.

As you might have guessed, there is file named ubygems that the original content of the variable caused to load. The strange name is in fact chosen only to make the whole command sound reasonable. All it does is load rubygems.rb, which initialises the Gems engine, enabling programs to use additional libraries.

No comments: