Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Block with two parameters

Tags:

ruby

I found this code by user Hirolau:

def sum_to_n?(a, n)
  a.combination(2).find{|x, y| x + y == n}
end

a = [1, 2, 3, 4, 5]
sum_to_n?(a, 9)  # => [4, 5]
sum_to_n?(a, 11) # => nil

How can I know when I can send two parameters to a predefined method like find? It's not clear to me because sometimes it doesn't work. Is this something that has been redefined?

like image 884
Luis Flores Avatar asked Nov 17 '15 20:11

Luis Flores


1 Answers

If you look at the documentation of Enumerable#find, you see that it accepts only one parameter to the block. The reason why you can send it two, is because Ruby conveniently lets you do this with blocks, based on it's "parallel assignment" structure:

[[1,2,3], [4,5,6]].each {|x,y,z| puts "#{x}#{y}#{z}"}
# 123
# 456

So basically, each yields an array element to the block, and because Ruby block syntax allows "expanding" array elements to their components by providing a list of arguments, it works.

You can find more tricks with block arguments here.

a.combination(2) results in an array of arrays, where each of the sub array consists of 2 elements. So:

a = [1,2,3,4]
a.combination(2)
# => [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

As a result, you are sending one array like [1,2] to find's block, and Ruby performs the parallel assignment to assign 1 to x and 2 to y.

Also see this SO question, which brings other powerful examples of parallel assignment, such as this statement:

a,(b,(c,d)) = [1,[2,[3,4]]]
like image 185
AmitA Avatar answered Sep 22 '22 14:09

AmitA