How do I create a reusable block/proc/lambda in Ruby? - ruby

I want to create a filter, and be able to apply it to an array or hash. For example:
def isodd(i)
i % 2 == 1
end
The I want to be able to use it like so:
x = [1,2,3,4]
puts x.select(isodd)
x.delete_if(isodd)
puts x
This seems like it should be straight forward, but I can't figure out what I need to do it get it to work.

Create a lambda and then convert to a block with the & operator:
isodd = lambda { |i| i % 2 == 1 }
[1,2,3,4].select(&isodd)

puts x.select(&method(:isodd))

You can create a named Proc and pass it to the methods that take blocks:
isodd = Proc.new { |i| i % 2 == 1 }
x = [1,2,3,4]
x.select(&isodd) # returns [1,3]
The & operator converts between a Proc/lambda and a block, which is what methods like select expect.

If you are using this in an instance, and you do not require any other variables outside of the scope of the proc (other variables in the method you're using the proc in), you can make this a frozen constant like so:
ISODD = -> (i) { i % 2 == 1 }.freeze
x = [1,2,3,4]
x.select(&ISODD)
Creating a proc in Ruby is a heavy operation (even with the latest improvements), and doing this helps mitigate that in some cases.

Related

Composing functions that yield in ruby

New to ruby language. I'm aware that ruby has then keyword to compose blocks and << for proc objects to compose proc. However, the question I have focuses on named functions that yield value to each other. I'm wondering what is the best way to implement such pipeline paradigm in ruby.
Consider the following code I came up with. I don't know if this is idiomatic.
# #param [Proc] lproc
# #param [Proc] rproc
def then_proc(lproc, rproc)
proc { |x| lproc.call(x, &rproc) }
end
def n(x)
yield x
end
def branch(x)
yield x + 1 if x > 2
0
end
def add_one(x)
x + 1
end
then_proc(method(:n).to_proc,
then_proc(method(:branch).to_proc, method(:add_one).to_proc)).call 2
=> 0
then_proc(method(:n).to_proc,
then_proc(method(:branch).to_proc, method(:add_one).to_proc)).call 3
=> 4
To me this is more similar to the forms of pipelines seen in other programming languages (Promise in javascript, for example), because functions can have branches to not yield and terminate early, whereas then requires the pipeline to be completely executed. I'm wondering if there is some mechanism in ruby that can achieve this. If not, how would go about this problem?
Thank you.
Clarification on the question
I would like to build a pipeline using a series of named functions that might but not necessarily yield to a block. Per my understanding, in the existing ruby then/yield_self function, the block is always invoked, which is not the intention. Notice in the toy example I gave, the final add_one block is only executed if previous branch function receives x > 2.
I would like to build a pipeline using a series of named functions that might but not necessarily yield to a block.
A method does not need to yield.
The following implements a conditional using procs:
def _if(v, cond, yes, no = nil)
if cond.call(v)
yes.call(v)
else
no&.call(v)
end
end
cond = lambda { |v| v > 2 }
yes = lambda { |v| v + 1 }
no = lambda { |v| 0 }
_if(1, cond, yes, no)
_if(3, cond, yes, no)
_if(1, cond, yes)

Creating a Matrix class in ruby. The [] method

I've been assigned to create a new matrix class. I cannot use the require 'Matrix'.
I have this to access the element of the matrix, where #matrix is an array of arrays.
def [] (i, j)
#matrix[i][j]
end
if i try to access it like this:
#a[0][0]
it wont work. (wrong number of arguments)
but if i do it like this:
#a.[](0,0)
or
#a[0,0]
it works just fine.
Any ideas on how to make it work?
def [] (i, j)
#matrix[i][j]
end
According to the method [] it needs 2 arguments. But #a[0][0] doesn't do that,as here you are passing the method [] only 1 argument,ie.e 0. only. So you got the error. But #a.[](0,0) or #a[0,0] are perfect,as you are sending 2 arguments to the method []. When you write #a[0,0],then Ruby internally does the method call as #a.[](0,0).
how would you modify the code so #a[0][0] works?
Here is a code example:
class Matrix
def initialize(a)
#matrix=a
end
def [](*a)
a.size == 1 ? #matrix[*a] : #matrix[a.first][a.last]
end
end
a = [[1,2,3],[4,7,5],[11,21,33]]
m = Matrix.new(a)
p m[2,2] # => 33
You need to write a method that either calls it self recursively or checks how many arguments that are passed to the function. It is hard to say if this works as I do not have you entire class, but something like this might work:
def [] (*cords)
return #matrix[*cords] if cords.size == 1
#matrix[cords.first][cords.last]
end
Or a recursive version that works for any number dimensions:
def [] (*cords)
cords.inject(#matrix){|m, c| m[c]}
end
def [](i)
#matrix[i]
end
would do it, I guess. FWIW, Ruby's Matrix has [] implemented same as you: [](i,j)

In Ruby, how can I collect each new element passing through a method into an array?

I'm creating a small prime number program, and am confused about one thing.
I have a function called create_numbers, that generates numbers and passes them to a new function called check_for_primes, which passes only prime numbers to a final function called count_primes. I want to collect each prime into an array in the function count_primes, but for some reason each number is collected as its own array.
Any idea of what I'm doing wrong?
Here is the code:
def create_numbers
nums = 1
while nums < 100
nums = nums + 2
check_for_primes(nums)
end
end
def count_primes(nums)
array = []
array << nums
puts array.inspect
end
def check_for_primes(nums)
(2...nums).each do |i|
if nums%i == 0
nums = false
break
end
end
if nums != false
count_primes(nums)
end
end
create_numbers
Try this:
START = 1
STEP = 2
class Integer
def prime?
return if self < 2
(2...self).each do |i|
return if self % i == 0
end
true
end
end
def create_numbers
num = START
while (num + STEP) < 100
num += STEP
primes << num if num.prime?
end
end
def primes
#primes ||= []
end
create_numbers
p primes
When you want to save the 'state' of something, put it in an instance variable (#var).
It'll be accessible outside of the current function's scope.
Also, try naming your variables differently. For instance, instead of 'nums', in the
create_numbers method, use 'num'. Since the variable is only referencing one number at a
time and not a list of numbers, naming it in the plural will confuse people (me included)...
Hope it helps,
-Luke
each time into count_primes you put a value into array (which should have a better name, btw). Unfortunately, each time it's a new variable called array and since no one outside the function can see that variable it's lost when the function ends. If you want to save the values you've already found you'll need to set some state outside your function.
I can think of 2 quick solutions. One would be to declare your storage at the top of create_numbers and pass it into both functions.
def count_primes(num, arr)
def check_for_primes(nums, arr)
The other would be to set a variable outside all the functions, $array, for example to hold the values.
$array = []
...
$array << num
Since the scope of $array is global (i.e. all functions have access to it) you have access to it from anywhere in the file and can just add things to it in count primes. Note that using globals in this way is generally considered bad style and a more elegant solution would pass parameters and use return values.

How do I dynamically decide which hash to add a value to?

I have a class that has hashes in various stages of "completion". This is to optimize so that I don't have to keep recreating hashes with root data that I already know. For example this is a counter called #root that would serve as a starting point.
{3=>4, 4=>1, 10=>3, 12=>5, 17=>1}
and it took key+key+key+key+key number of iterations to create #root. But now I have all combinations of [x,y] left to be added to the counter and individually evaluated. So I could do it like:
a = (1..52)
a.combination{|x,y|
evaluate(x,y)
}
But instead of I would like to do this:
a.each{|x|
evaluate(x, "foo")
a.each {|y| evaluate(y, "bar")}
}
Where i have a method like this to keep track of the hash at each state:
def evaluate index, hsh
case hsh
when "root"
#root.key?(index) ? #root[index] += 1 : #root[index] = 1
when "foo"
#foo = #root.clone
#foo.key?(index) ? #foo[index] += 1 : #foo[index] = 1
when "bar"
#bar = #foo.clone
#bar.key?(index) ? #bar[index] += 1 : #bar[index] = 1
end
end
But there is alot of repetition in this method. Is there a way that I could do this dynamically without using eval?
Instead of using hsh as a string descriptor, you can directly pass the hash object as parameter to your method evaluate? E.g. instead of evaluate(x, "foo") you write
#foo = #root.clone
evaluate(x, #foo)
Also note the #root.clone in your code overwrites the field several times inside the loop.
Additionally if you use a default initializer for your hash you save quite some logic in your code. E.g. the code lines
h = Hash.new{0}
...
h[index] += 1
will set the default value to zero if non was set for index. Thus you do not have to take care of the special case inside your evaluate method.

Passing a method as a parameter in Ruby

I am trying to mess around a little bit with Ruby. Therefor I try to implement the algorithms (given in Python) from the book "Programming Collective Intelligence" Ruby.
In chapter 8 the author passes a method a as parameter. This seems to work in Python but not in Ruby.
I have here the method
def gaussian(dist, sigma=10.0)
foo
end
and want to call this with another method
def weightedknn(data, vec1, k = 5, weightf = gaussian)
foo
weight = weightf(dist)
foo
end
All I got is an error
ArgumentError: wrong number of arguments (0 for 1)
The comments referring to blocks and Procs are correct in that they are more usual in Ruby. But you can pass a method if you want. You call method to get the method and .call to call it:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
You want a proc object:
gaussian = Proc.new do |dist, *args|
sigma = args.first || 10.0
...
end
def weightedknn(data, vec1, k = 5, weightf = gaussian)
...
weight = weightf.call(dist)
...
end
Just note that you can't set a default argument in a block declaration like that. So you need to use a splat and setup the default in the proc code itself.
Or, depending on your scope of all this, it may be easier to pass in a method name instead.
def weightedknn(data, vec1, k = 5, weightf = :gaussian)
...
weight = self.send(weightf)
...
end
In this case you are just calling a method that is defined on an object rather than passing in a complete chunk of code. Depending on how you structure this you may need replace self.send with object_that_has_the_these_math_methods.send
Last but not least, you can hang a block off the method.
def weightedknn(data, vec1, k = 5)
...
weight =
if block_given?
yield(dist)
else
gaussian.call(dist)
end
end
...
end
weightedknn(foo, bar) do |dist|
# square the dist
dist * dist
end
But it sounds like you would like more reusable chunks of code here.
You can pass a method as parameter with method(:function) way. Below is a very simple example:
def double(a)
return a * 2
end
=> nil
def method_with_function_as_param( callback, number)
callback.call(number)
end
=> nil
method_with_function_as_param( method(:double) , 10 )
=> 20
The normal Ruby way to do this is to use a block.
So it would be something like:
def weightedknn(data, vec1, k = 5)
foo
weight = yield(dist)
foo
end
And used like:
weightedknn(data, vec1) { |dist| gaussian( dist ) }
This pattern is used extensively in Ruby.
You can use the & operator on the Method instance of your method to convert the method to a block.
Example:
def foo(arg)
p arg
end
def bar(&block)
p 'bar'
block.call('foo')
end
bar(&method(:foo))
More details at http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
You have to call the method "call" of the function object:
weight = weightf.call( dist )
EDIT: as explained in the comments, this approach is wrong. It would work if you're using Procs instead of normal functions.
I would recommend to use ampersand to have an access to named blocks within a function. Following the recommendations given in this article you can write something like this (this is a real scrap from my working program):
# Returns a valid hash for html form select element, combined of all entities
# for the given +model+, where only id and name attributes are taken as
# values and keys correspondingly. Provide block returning boolean if you
# need to select only specific entities.
#
# * *Args* :
# - +model+ -> ORM interface for specific entities'
# - +&cond+ -> block {|x| boolean}, filtering entities upon iterations
# * *Returns* :
# - hash of {entity.id => entity.name}
#
def make_select_list( model, &cond )
cond ||= proc { true } # cond defaults to proc { true }
# Entities filtered by cond, followed by filtration by (id, name)
model.all.map do |x|
cond.( x ) ? { x.id => x.name } : {}
end.reduce Hash.new do |memo, e| memo.merge( e ) end
end
Afterwerds, you can call this function like this:
#contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == #current_user
end
If you don't need to filter your selection, you simply omit the block:
#categories = make_select_list( Category ) # selects all categories
So much for the power of Ruby blocks.
Similarly to a Proc or a method call, you can also pass a lambda as weightf parameter :
def main
gaussian = -> (params) {
...
}
weightedknn(data, vec1, k = 5, gaussian, params)
# Use symbol :gaussian if method exists instead
end
def weightedknn(data, vec1, k = 5, weightf, params)
...
weight = weightf.call(params)
...
end
you also can use "eval", and pass the method as a string argument, and then simply eval it in the other method.

Resources