我正在使用一些惰性迭代,并且希望能够为此迭代指定多个步骤。这意味着我希望该步骤在a
和b
之间切换。所以,如果我把它作为一个范围(不是为了简化而懒惰)
(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中是否可行?
答案 0 :(得分:3)
您可以使用cycle和Enumerator的组合:
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非常大,则可能会有用。