有没有办法在Ruby中指定多步骤?

时间:2017-01-01 20:49:40

标签: ruby

我正在使用一些惰性迭代,并且希望能够为此迭代指定多个步骤。这意味着我希望该步骤在ab之间切换。所以,如果我把它作为一个范围(不是为了简化而懒惰)

(1..20).step(2, 4)

我希望我的结果范围是

1 # + 2 =
3 # + 4 = 
7 # + 2 =
9 # + 4 =
13 # + 2 = 
15 # + 4 = 
19 # + 2 = 21 (out of range, STOP ITERATION)

然而,我无法想办法做到这一点。这在Ruby中是否可行?

2 个答案:

答案 0 :(得分:3)

您可以使用cycleEnumerator的组合:

class Range
  def multi_step(*steps)
    a = min
    Enumerator.new do |yielder|
      steps.cycle do |step|
        yielder << a
        a += step
        break if a > max
      end
    end
  end
end

p (1..20).multi_step(2, 4).to_a
#=> [1, 3, 7, 9, 13, 15, 19]

请注意,第一个元素是1,因为(1..20).step(2)的第一个元素也是1.

考虑exclude_end?

p (1...19).multi_step(2, 4).to_a
#=> [1, 3, 7, 9, 13, 15]

可能很懒:

p (0..2).multi_step(1,-1).first(20)
#=> [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
p (0..Float::INFINITY).multi_step(*(1..100).to_a).lazy.map{|x| x*2}.first(20)
#=> [0, 2, 6, 12, 20, 30, 42, 56, 72, 90, 110, 132, 156, 182, 210, 240, 272, 306, 342, 380]

以下是FizzBuzz的变体,它会生成3或5但不是15的所有倍数:

p (3..50).multi_step(2,1,3,1,2,6).to_a
#=> [3, 5, 6, 9, 10, 12, 18, 20, 21, 24, 25, 27, 33, 35, 36, 39, 40, 42, 48, 50]

答案 1 :(得分:1)

Ruby没有内置的方法来踩多个值。但是,如果您实际上不需要惰性方法,则可以将Enumerable#cycle与累加器一起使用。例如:

range = 1..20
accum = range.min
[2, 4].cycle(range.max) { |step| accum += step; puts accum }

或者,您可以使用Enumerator::Lazy构建自己的惰性枚举器。对于给定的示例来说,这似乎有些过分,但如果您的Range object非常大,则可能会有用。