2017-02-10 41 views
2

我想知道是否有办法生成一个数组,例如从0开始,增加1直到达到3,然后减少1直到达到0再次,如创建一个包含在两个边界之间振荡的值的数组

[0,1,2,3,2,1,0]

如果我能提前指定数组中值的数量,这将是巨大的。例如,如果我可以设置下限(0),上限(3),增量(1)和数组长度(9):

[] .oscillate(0,3,1,9)会给我这样的:

[0,1,2,3,2,1,0,1,2]

截至目前,我能想出的最好的事情是这样的:

values = [] 
    until values.count >= 9 
    values.pop 
    x=0 
    values << x && x+=1 while x < 3 
    values << x && x-=1 while x >= 0 

    end 

回答

1

试试这个

def oscillate(a, b, step, num) 
    ramp_up = a.step(b, step).entries 
    ramp_down = ramp_up.drop(1).reverse.drop(1) 
    ramp_up.concat(ramp_down).cycle.take(num) 
end 

这是如何工作的?

  • 创建ramp_upramp_down
  • 阵列
  • 地连接了两个阵列
  • cycle返回一个不断重复的枚举
  • take物化从枚举num元件。除了在评论中提出的建议,这不会重新计算任何事情。它只是实现枚举器的条目。
+0

这很好,但它会重新计算每次拍摄的整个顺序。确定小序列,但我建议添加memoization,如果序列很大。 –

+0

谢谢你的方法! – MattF

+0

@mattf很高兴听到这是有帮助的!如果你喜欢这个答案,考虑接受它与复选标记。 – akuhn

3

有趣的运动!您正在寻找triangle wave。 维基百科上的分子式为:用于标准形状(-1和1之间),但这里的任何波位置,周期和幅度的适配版本:

def triangle_wave(min, max, increment, length, offset = 0) 
    amplitude = max - min 
    period = 2 * amplitude 
    Array.new(length) do |i| 
    min + ((increment * (i + offset) - amplitude) % period - amplitude).abs 
    end 
end 

puts triangle_wave(0, 3, 1, 9) == [0, 1, 2, 3, 2, 1, 0, 1, 2] 
# true 

p triangle_wave(-3, 3, 1, 20) 
# => [-3, -2, -1, 0, 1, 2, 3, 2, 1, 0, -1, -2, -3, -2, -1, 0, 1, 2, 3, 2] 

p triangle_wave(5, 9, 2, 9) 
# => [5, 7, 9, 7, 5, 7, 9, 7, 5] 

p triangle_wave(0, 1, 0.25, 9) 
# => [0.0, 0.25, 0.5, 0.75, 1.0, 0.75, 0.5, 0.25, 0.0] 

p triangle_wave(-3, 0, 1, 9, 3) 
# => [0, -1, -2, -3, -2, -1, 0, -1, -2] 

p triangle_wave(0, 1, 1, 9) 
# => [0, 1, 0, 1, 0, 1, 0, 1, 0] 

min应该比max下,increment应该是正和max-min应该可以被increment整除。这些是对输入的限制,而不是对输出的限制:可以生成任何波形。

+0

非常感谢您的帮助! – MattF

2

此问题可能是使用Ruby的flip-flop operator的教科书示例。

由于只有当存在非负整数steps这样的high = low + steps * increment时,我已经用steps替换了方法的参数high

def oscillate(low, steps, increment, length) 
    high = low + steps * increment 
    n = low 
    length.times.each_with_object([]) do |_,a| 
    a << n 
    n += (n==low)..(n==high-increment) ? increment : -increment 
    end 
end 

oscillate(0,3,1,9) 
    #=> [0, 1, 2, 3, 2, 1, 0, 1, 2] 

oscillate(-1, 4, 2, 16)  
    #=> [-1, 1, 3, 5, 7, 5, 3, 1, -1, 1, 3, 5, 7, 5, 3, 1] 

为了表明这里发生了什么,我将修改代码一点,增加一些puts语句,然后用第一个例子运行它。

def oscillate(low, steps, increment, length) 
    high = low + steps * increment 
    puts "high = #{high}" 
    n = low 
    length.times.each_with_object([]) do |_,a| 
    a << n 
    diff = (n==low)..(n==high-increment) ? increment : -increment 
    print "n=#{n}, a<<n=#{a}, diff=#{diff}, " 
    n += diff 
    puts "n+=diff=#{n}" 
    end 
end 

oscillate(0,3,1,9) 
high = 3 
n=0, a<<n=[0],       diff= 1, n+=diff=1 
n=1, a<<n=[0, 1],      diff= 1, n+=diff=2 
n=2, a<<n=[0, 1, 2],     diff= 1, n+=diff=3 
n=3, a<<n=[0, 1, 2, 3],    diff=-1, n+=diff=2 
n=2, a<<n=[0, 1, 2, 3, 2],    diff=-1, n+=diff=1 
n=1, a<<n=[0, 1, 2, 3, 2, 1],   diff=-1, n+=diff=0 
n=0, a<<n=[0, 1, 2, 3, 2, 1, 0],  diff= 1, n+=diff=1 
n=1, a<<n=[0, 1, 2, 3, 2, 1, 0, 1], diff= 1, n+=diff=2 
n=2, a<<n=[0, 1, 2, 3, 2, 1, 0, 1, 2], diff= 1, n+=diff=3 
    #=> [0, 1, 2, 3, 2, 1, 0, 1, 2] 
+0

不错。这是我第一次看到触发器的合法使用。 –