2012-08-06 38 views
3

我想編寫一個在任意維度上跨越空間的ruby程序。在ruby中創建任意深度的嵌套循環

在3個維度我在做什麼看起來像這樣:

x_range = (-1..1) 
y_range = (-1..1) 
z_range = (-1..1) 

step_size = 0.01 

x_range.step(step_size) do |x| 
    y_range.step(step_size) do |y| 
    z_range.step(step_size) do |z| 

     # do something with the point x,y,z 

    end 
    end 
end 

我想爲n尺寸

回答

1

遞歸可以輕鬆完美地解決這類問題。以下代碼適合任意數量的維度,還有各種長度的範圍

def traversal(ranges, step_size, conjunction = [], &blk) 
    ranges[0].step(step_size) do |x| 
    conjunction.push(x) 
    if ranges.size > 1 
     traversal(ranges[1..-1], step_size, conjunction, &blk) 
    else 
     blk.call(conjunction) if block_given? 
     conjunction.pop 
    end 
    end 
    conjunction.pop 
end 

執行命令(尺寸= 4,長度= 3,3,4,2)

x = (1..3) 
y = (4..6) 
z = (7..10) 
w = (100..101) 
test_data = [x, y, z, w] 
step_size = 1 

traversal(test_data, step_size) do |x| 
    puts "Point: #{x.join('-')}" 
end 

輸出:(共計72點,這是3 * 3 * 4 * 2)

Point: 1-4-7-100 
Point: 1-4-7-101 
Point: 1-4-8-100 
Point: 1-4-8-101 
Point: 1-4-9-100 
Point: 1-4-9-101 
Point: 1-4-10-100 
Point: 1-4-10-101 
Point: 1-5-7-100 
Point: 1-5-7-101 
Point: 1-5-8-100 
Point: 1-5-8-101 
Point: 1-5-9-100 
Point: 1-5-9-101 
Point: 1-5-10-100 
Point: 1-5-10-101 
Point: 1-6-7-100 
Point: 1-6-7-101 
Point: 1-6-8-100 
Point: 1-6-8-101 
Point: 1-6-9-100 
Point: 1-6-9-101 
Point: 1-6-10-100 
Point: 1-6-10-101 
Point: 2-4-7-100 
Point: 2-4-7-101 
Point: 2-4-8-100 
Point: 2-4-8-101 
Point: 2-4-9-100 
Point: 2-4-9-101 
Point: 2-4-10-100 
Point: 2-4-10-101 
Point: 2-5-7-100 
Point: 2-5-7-101 
Point: 2-5-8-100 
Point: 2-5-8-101 
Point: 2-5-9-100 
Point: 2-5-9-101 
Point: 2-5-10-100 
Point: 2-5-10-101 
Point: 2-6-7-100 
Point: 2-6-7-101 
Point: 2-6-8-100 
Point: 2-6-8-101 
Point: 2-6-9-100 
Point: 2-6-9-101 
Point: 2-6-10-100 
Point: 2-6-10-101 
Point: 3-4-7-100 
Point: 3-4-7-101 
Point: 3-4-8-100 
Point: 3-4-8-101 
Point: 3-4-9-100 
Point: 3-4-9-101 
Point: 3-4-10-100 
Point: 3-4-10-101 
Point: 3-5-7-100 
Point: 3-5-7-101 
Point: 3-5-8-100 
Point: 3-5-8-101 
Point: 3-5-9-100 
Point: 3-5-9-101 
Point: 3-5-10-100 
Point: 3-5-10-101 
Point: 3-6-7-100 
Point: 3-6-7-101 
Point: 3-6-8-100 
Point: 3-6-8-101 
Point: 3-6-9-100 
Point: 3-6-9-101 
Point: 3-6-10-100 
Point: 3-6-10-101 
0

如果範圍不是太大,你可以做這樣的事情做同樣的:

n = 5 # 5 dimentions 
x = (-1..1).to_a 
x.product(*[x]*(n-1)).each {|i| p i} 

結果:

[-1, -1, -1, -1, -1] 
[-1, -1, -1, -1, 0] 
[-1, -1, -1, -1, 1] 
[-1, -1, -1, 0, -1] 
[-1, -1, -1, 0, 0] 
[-1, -1, -1, 0, 1] 
[-1, -1, -1, 1, -1] 
[-1, -1, -1, 1, 0] 
[-1, -1, -1, 1, 1] 
[-1, -1, 0, -1, -1] 
[-1, -1, 0, -1, 0] 
# skipped 
2

這是想到我的第一件事就是:

def enumerate(nDimens, bottom, top, step_size) 
    bottom = (bottom/step_size).to_i 
    top = (top /step_size).to_i 

    range = (bottom..top).to_a.map{ |x| x * step_size } 
    return range.repeated_permutation(nDimens) 
end 

stepper = enumerate(4, -1, 1, 0.1) 

loop do 
    puts "#{stepper.next()}" 
end 

這將產生:

[-1.0, -1.0, -1.0, -1.0] 
[-1.0, -1.0, -1.0, -0.9] 
[-1.0, -1.0, -1.0, -0.8] 
# Lots more... 
[1.0, 1.0, 1.0, 0.8] 
[1.0, 1.0, 1.0, 0.9] 
[1.0, 1.0, 1.0, 1.0] 

這是假設所有維度具有相同的範圍,但它會很容易調整,如果由於某些原因,這並不成立。

0

這就是你可以做的...這裏是一個迭代器的例子。

#next(l[dim] array of lower ranges ,h[dim] = upper ranges, step[dim], dim = dimensions -1, curr[dim] = current state in dim dimensions) 
def nextx(l ,h, step, dim, curr) 
    x = dim 
    update= false 
    while (update==false) 
     if curr[x] == h[x] 
      if x > 0 
       x = x-1 
      else 
       exit 
      end 

     else 
      curr[x]= curr[x]+step[x] 
      while (x < dim) 
       x = x+1 
       curr[x] = l[x] 
      end 
      update = true 
     end 
    end 
    return curr 
end 


l = [0,0,0] 
h = [3,3,3] 
step = [1,1,1] 
currx = [0,0,2] 

i = 0 
while i < 70 
    currx = nextx(l, h, step, 2, currx) 
    puts currx.inspect 
    i=i+1 
end