From: Jan Svitok Date: 2007-01-12T08:20:27+09:00 Subject: Re: A loop within another loop.. On 1/11/07, Mike Harris wrote: > Dominic Son wrote: > > >Hi. Hopefully you will see the code and see what I'm trying to do, and > >see the problem. The loop seems messy, but my method to help with eye > >strain is to match up the do-end's down an imaginary column... ie: > > > >array.each # do # |i| > > puts i # # <-imaginary column > > # end # > > > >##### So here's the code. ########### > > > >def foo(argument1, argument2) #1 > >user = [2,5] > > > >user.each do |bar| > >output = [] #2 > >argument1.each do |i| #3 > > > > if i.parent.id == bar.id #4 > > output << i.parent.name > > end > > end > > > > argument2.each do |i| > > if i.parent.id == bar.id > > output << i.name > > end > > end > >return output > > end > > > >Comments: > >#1 - argument comes in as arrays > >#2 - let's setup the var that will return the array of collected data > >#3 - i think this is where the problem may lie. > >#4 - parent is an acts_as_tree method inside rails, just grabs the > >parant. > > notice how i call the iterating variable 'bar' inside this new > >loop..is this legal? > > > >My intuition tells me there's probably a better method to do this. Any > >comments, suggestions would be appreciated. > > > >Dominic > > > > > > > First, your code is missing an end. Second, making the end to the block > start is easy with the standard convention > > This is infinitely easier (to me, and 99.9% of programmers) than moving > the end out to match the do. Do you find this hard to read? You seem > to have no problem matching the end to its matching if. 1. The main question: is this legal - yes, it's perfectly legal, it's one of the blocks' features. The blocks are closures, i.e. they keep they outer context. This is used when you pass a block between functions: def fun2 yield 10 end def fun1 a= 5 puts fun2 do |i| # yield 10 will set i=10 i + a # here block has access to a even though it is called from fun2 end # => 15 end 2. few changes to the code: (I changed bar.id to just bar - it seems to me that's what you want) def foo(argument1, argument2) user = [2,5] output = [] user.each do |bar| output += argument1.select{|i| i.parent.id == bar}.map{|i| i.parent.name} output += argument2.select{|i| i.parent.id == bar}.map{|i| i.name} end output end see Enumerable#select, Enumerable#map for explanation. shortly: "from argument1 array select those that fulfill the condition and for each of them get i.parent.name"