tags:

views:

252

answers:

5

I have varying number of arrays within one giant array. (is this the right approach?)

parentArray = [[array],[array2],....]

how can i create a series of nested loops for each consecutive array ? So creating array loops within the previous one.

parentArray.each do |eacharray|

    array.each do |eacharray1|
     array2.each do |eacharray2|
      array3.each do |eacharray3|
       arrayN.each do ....
         .....
          .....

     ...
    ...
   end    
  end
 end
end

@Justice, basically i have many arrays. the first array is the "parent", then the next array is the children of each value's of "parent". if there is another array, then it will be the children of each value of immediate previous array.

EXample:

A spider will visit the first page containing links, and store this as array. spide visits first link on the first page, and discovers lot more links at this level, and stores this as array. Spider keeps going and keeps discovering more and more links until it goes to the deepest level.

I end up with

rootArray = [arrayLinks, arrayLink2, arrayLinks3....]

simply doing .flatten will destroy all depth relationship.

what is required is recursive (tree?) routine that will do a recursive nested loop starting with the very first array (aka arrayLinks), and building another loop inside the first, and so on.

+1  A: 

If all you care about is to run the same instruction for all levels, then you can simply flatten the array (makes it one dimensional) and then run your instruction:

parentArray.flatten.each do |element|
   puts element
end

This will recursively flatten all dimensions to a single dimension. I believe this is only available in Ruby 1.9 and above.

JRL
nono. one dimensional is not what im aiming for . pleas read my message directed @Justice.
gweg
@gweg: it won't modify your multi-dimensional array (for that you'd have to use flatten!), it will create a copy allowing you to run instructions on each element without having to nest any statements.
JRL
that will simply loop through all of the arrays. this is not what i want.
gweg
`flatten` is available in Ruby 1.8 as well.
Geo
+1  A: 

I've solved similar problems using recursion.

def processArrays(parents, arrs)
  if not arrs.empty?
    a0 = arrs[0]
    parents.push(a0)
    a0.each {|a0x| processArrays(parents, arrs[1..-1])
    parents.pop
  end
end

You call it with processArrays([], topArray) and each level will have the array of parents (so far) and an array of remaining arrays to work with.

Carl Smotricz
A: 
    parentArray = [[1,2],[3,4,['alpha','beta']],'a','b','c']

def processArray(array,depth)
  array.each do |element|
       if element.is_a?(Array)
          processArray(element,depth+1)
       else
          puts "Element at Depth #{depth.to_s} is #{element.to_s}"
       end
  end
end


processArray(parentArray,1)

this outputs:

Element at Depth 2 is 1
Element at Depth 2 is 2
Element at Depth 2 is 3
Element at Depth 2 is 4
Element at Depth 3 is alpha
Element at Depth 3 is beta
Element at Depth 1 is a
Element at Depth 1 is b
Element at Depth 1 is c
cgr
A: 

I've created a script that assumes that the inner loop is rewritten as a method called innerloop(arrayOfCurrentValues). The method gets called as many times as there are combinations to be run, each time the array passed contains the currently selected value from each nested loop, in order from outermost loop to innermost loop.

The array a here is your parentArray.

Here's the code and a demo:

Script started on Sat Nov  7 21:55:40 2009
bash-3.2$ cat loops.rb
a = [[1,2,3],[:a,:b],[51,52,53,54]]

def innerloop(arrayOfCurrentValues)
  puts "innerloop("+arrayOfCurrentValues.inspect+")"
end

def traverse(accumulated,params, index) 
 if (index==params.size)
  return innerloop(accumulated) 
 end

 currentParam = params[index]
 currentParam.each do |currentElementOfCurrentParam|
  traverse(accumulated+[currentElementOfCurrentParam],params, index+1)
 end

end


traverse([],a,0)



bash-3.2$ ruby loops.rb
innerloop([1, :a, 51])
innerloop([1, :a, 52])
innerloop([1, :a, 53])
innerloop([1, :a, 54])
innerloop([1, :b, 51])
innerloop([1, :b, 52])
innerloop([1, :b, 53])
innerloop([1, :b, 54])
innerloop([2, :a, 51])
innerloop([2, :a, 52])
innerloop([2, :a, 53])
innerloop([2, :a, 54])
innerloop([2, :b, 51])
innerloop([2, :b, 52])
innerloop([2, :b, 53])
innerloop([2, :b, 54])
innerloop([3, :a, 51])
innerloop([3, :a, 52])
innerloop([3, :a, 53])
innerloop([3, :a, 54])
innerloop([3, :b, 51])
innerloop([3, :b, 52])
innerloop([3, :b, 53])
innerloop([3, :b, 54])
bash-3.2$ exit
exit

Script done on Sat Nov  7 21:55:51 2009
cartoonfox
calling params.size each time traverse() is called is inefficient - and you could certainly wrap this code in a class that has the size of params evaluated once and held in a field. You could even refactor the call to innerLoop(a) to be a block passed into the object...
cartoonfox
A: 
module Scratch
  def self.recur(arr, depth, &fn)
    arr.each do |a| 
      a.is_a?(Array) ?  recur(a, depth+1, &fn) : fn.call(a, depth)
    end
  end
  arr = [[1, 2, 3], 4, 5, [6, 7, [8, 9]]]
  recur(arr, 0) { |x,d| puts "#{d}: #{x}" }
end
wentbackward