user12341234 user12341234 - 5 months ago 10
Ruby Question

Bind and Destructure block arguments

In ruby is there a way to simultaneously bind the argument of a block to a local as well as destructure it?

Googling hasn't found me anything and playing in IRB has been fruitless, but I thought I recalled functionality that would work similar to the following:

>> [[1, 2], [3, 4]].map{|x@(y, z)| [x, y, z]}
=> [[[1, 2], 1, 2], [[3, 4], 3, 4]]


Where
x
captures each top-level element of the iterated object (in this case first
[1, 2]
, then
[3, 4]
) and
y
and
z
capture the sub-elements of the object in inside of
x
(
1
then
3
and
2
then
4
, respectively).

Edit



It just occurred to me that the feature I projected into Ruby actually comes from Haskell: What does the "@" symbol mean in reference to lists in Haskell?

Still, is there an elegant way to achieve the same in Ruby?

Answer

I'd want a solution that assigned [[1, 2], [3, 4]] to x, [1, 2] to y and [3, 4] to z

How about this:

irb(main):001:0> y, z = x = [[1, 2], [3, 4]]
=> [[1, 2], [3, 4]]
irb(main):002:0> y
=> [1, 2]
irb(main):003:0> z
=> [3, 4]
irb(main):004:0> x
=> [[1, 2], [3, 4]]

Update (Let's put this into a block)

Is this okey for you:

[[1, 2], [3, 4]].tap do |arr| 
  y, z = x = arr 
  p x # => [[1, 2], [3, 4]]
  p y # => [1, 2]
  p z # => [3, 4]
end
Comments