Usage of Pipes in Ruby Loops

ruby

Solution

When you have a simple array, the following things happen:

arr = [1,2,3,4]

arr.each do |x|
  p x
end
1
2
3
4
=> [1,2,3,4]

arr.each do |x,y|
  p x
  p y
end
1
nil
2
nil
3
nil
4
nil
=> [1,2,3,4]

so if ruby doesn't know what to put into the block argument, it simply sets it to `nil`. Now consider a nested array:

arr = [[1,2],[3,4],[5,6]]

arr.each do |x|
  p x
end
[1, 2]
[3, 4]
[5, 6]
=> [[1,2],[3,4],[5,6]]

arr.each do |x,y|
  p x
  p y
end
1
2
3
4
5
6
=> [[1,2],[3,4],[5,6]]

In this case, ruby assumes that you want to assign the two elements of the inner arrays to the block variables `x` and `y`. The same thing applies to hashes, where Ruby assigns the key and value to `x` and `y`:

hash = {1 => 2, 3 => 4, 5 => 6}

hash.each do |x,y|
  p x
  p y
end
1
2
3
4
5
6
=> {1=>2,3=>4,5=>6}

When you don't have enough elements in the nested arrays, the block variables are assigned `nil`, indeed. When there are too many of them, they are simply discarded:

arr = [[1,2,3],[4,5],[6]]

arr.each do |x,y|
  p x
  p y
end
1
2
4
5
6
nil
=> [[1,2,3],[4,5],[6]]

pretty straightforward!

EDIT:

As for your edited question: no, you cannot apply this 1:1 to Ruby code, you would have to manually apply the splat operator (`*`) to `subcats`. This way, ruby assigns all remaining elements to the 'splatted' block variable:

categories.each do |category,*subcats|
    puts "The main category is #{category} and the sub categories are: "
    subcats.each do |subcat|
        puts "#{subcat}, "
    end
end

although i would generate a comma-separated list of subcategories like this:

categories.each do |category,*subcats|
    puts "The main category is #{category} and the sub categories are: "
    puts subcats.join(', ')
end

EDIT 2:

Oh, and you would not handle a huge ugly evil multidimensional array by defining a lot of block parameters for its elements. You probably would iterate through it using nested loops as in almost every other language, if only because you never know how many elements it contains.

Problem

So, maybe I'm over-complicating something that isn't that hard, but here goes. In Ruby, there's a method of looping called .each. I think that this is very cool--but what I'm finding less cool is the amount of stuff written about the pipe that comes after it (or any other do-type loop in Ruby, it would seem). Sometimes there is a single thing in the pipe: ``` basket.each do |fruit| puts "This is a #{fruit}.\n" end ``` But sometimes, there are two things in this pipe, like so: ``` contacts.each do |name, profession| puts "#{name} is a #{profession}.\n" end ``` So what I'm wondering now, is it possible to have more than two items in that pipe? Like if I have a huge, big, and ugly multi-dim array? What if I add things to my pipe and they're not there? Will it give the value in the pipe nil? Or will it throw an error? Again, sorry if this is obvious to long-time Rubyists, but I came from the land of strictly typed variables, and I'm now leaving PHP land, too. :) EDIT So what if I have something like this: ``` categories = [["Bathroom", "Bathroom Fixtures", "Plumbing"], ["Ceiling Fixtures", "Chandeliers", "Flush Mounts", "Mini Chandeliers", "Semi-Flush Mounts", "Pendants", "Track Lighting", "Mini Pendants", "Directional", "Island/Pool Table", "Recessed Lighting"], ["Outdoor", "Exterior", "Landscape Lighting"], ["Fans", "Fans", "Fan Accessories"], ["Lamps", "Lamps", "Shades"], ["Wall Fixtures", "Sconces", "Foyer/Hall Lanterns"], ["Specialty", "Undercabinet", "Light Bulbs", "Lighting Controls", "Glass", "Specialty Items", "Utility"], ["Home Decor", "Decor/Home Accents", "Furniture"]] ``` Can I loop through it like this? ``` categories.each do |category, subcats| puts "The main category is #{category} and the sub categories are: " subcats.each do |subcat| puts "#{subcat}, " end end ```

Original source