我有一个非常大的范围需要遍历并找到满足特定约束的第一个元素.这在Ruby中已经可以高效地完成了.
# Runs until memory is exhausted _without_ lazy!
(1..).lazy.select { |i| i > 5 }.first
# => 6
然而,在我的用例中,我希望从范围的random interval开始迭代,如果到达范围末尾时没有元素通过判断,则从范围的开始处继续(直到再次达到随机间隔,如果需要).以Combining two different 'ranges' to one in ruby作为参考,我来到了...
letter = ('b'..'y').to_a.sample
[*letter..'z', *'a'...letter].map { |c| c.capitalize }.join
# => "FGHIJKLMNOPQRSTUVWXYZABCDE"
当然,我没有字母表作为遍历的范围,这只是一个小规模的例子,在我的用例中失败了.
-
*
(Splat)操作员并不懒 -
map
不是懒惰
通过更多的谷歌搜索和实验,我得出了以下 struct :
# lazy version of previous alphabet example
[(letter..'z'), ('a'...letter)].lazy.flat_map { |r| r.each.lazy }.map { |c| c.capitalize }.force.join
=> "FGHIJKLMNOPQRSTUVWXYZABCDE"
# Comparable to what I want
start = rand(2**64)
# => 15282219649142738977
[(start..2**64), (0...start)].lazy.flat_map { |r| r.each.lazy }.select { |i| i % 7 == 0 }.first(5)
# => [15282219649142738978, 15282219649142738985, 15282219649142738992, 15282219649142738999, 15282219649142739006]
iter = [(start..2**64), (0...start)].lazy.flat_map { |r| r.each.lazy }.select { |i| i % 7 == 0 }
# => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: [15282219649142738977..18446744073709551616, 0...15282219649142738977]>:flat_map>:select>
iter.next
# => 15282219649142738978
iter.next
# => 15282219649142738985
在我看来,这确实太复杂了,也许有人有更好的主意?
Thank you for your time,
Xavier.