1

I have A, an array of arrays of length 3. For example A = [[a1, b1, c3], [a2, b2, c2], [a3, b3, c3], [a4, b4, c4]]. Right now I am looping over it like this:

A.each do |elem|
  puts(elem[0].foo)
  puts(elem[1].bar)
  puts(elem[2].baz)
end

Since I am using a lot of different properties in the loop, the code gets pretty messy and unreadable. Plus, the local name elem[0] isn't very descriptive. Is there a way to use something like this?

A.each do |[a,b,c]|
  puts(a.foo)
  puts(b.bar)
  puts(c.baz)
end

I'm pretty new to ruby I don't really know where to look for something like this.

5
  • 1
    Try do |a,b,c| instead of do |[a,b,c]| Commented Oct 7, 2020 at 15:39
  • Thanks, works perfectly. Out of curiosity, what is this kind of thing called? Commented Oct 7, 2020 at 15:44
  • 1
    Multiple assignment, several languages have this feature including ruby Commented Oct 7, 2020 at 16:21
  • 2
    The Ruby docs refer to it as array decomposition. Note that the size of the array must be known to contain three elements to express the block variables as |a,b,c|. Commented Oct 7, 2020 at 17:30
  • 3
    What @CarySwoveland said; however if the array contains more than 3 elements but a and b are the imperative, one can use array decomposition with the splat (*) operator as well such that |a,b,*c| (it is customary to use *rest in place of *c). In this case a and b will be the first and second elements of the Array and *c will contain 0 or more elements that identify the rest of the Array. Commented Oct 7, 2020 at 19:00

1 Answer 1

4

Its known as de-structuring (or decomposition in the Ruby docs):

A.each do |(a,b,c)|
  puts(a.foo)
  puts(b.bar)
  puts(c.baz)
end

You can also use a splat (*) if the number of elements is unknown which will gather the remaining elements:

[[1, 2, 3, 4], [5, 6, 7, 8]].each do |(first, *rest)|
  puts "first: #{first}"
  puts "rest: #{rest}"
end


[[1, 2, 3, 4], [5, 6, 7, 8]].each do |(first, *middle, last)|
  puts "first: #{first}"
  puts "middle: #{middle}"
  puts "last: #{last}"
end
Sign up to request clarification or add additional context in comments.

2 Comments

Note that the parentheses are optional if the block is yielded with one parameter that is an array. Meaning that A.each do |a,b,c| would also work here.
@3limin4t0r true. I still do like them as they give a heads up that there is de-structuring going on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.