如何惰性连接 Ruby 范围?

问题描述 投票:0回答:1

我有一个非常大的范围来迭代并找到满足特定约束的第一个元素。这已经可以在 Ruby 中高效地完成。

# Runs until memory is exhausted _without_ lazy!
(1..).lazy.select { |i| i > 5 }.first
# => 6

但是,在我的用例中,我想以范围的“随机间隔”开始迭代,并且如果在到达范围末尾时没有元素通过检查,则从范围的开头继续(直到随机间隔)如果需要的话,再次达到间隔)。以 在 ruby 中将两个不同的“范围”组合为一个作为参考,我发现...... letter = ('b'..'y').to_a.sample [*letter..'z', *'a'...letter].map { |c| c.capitalize }.join # => "FGHIJKLMNOPQRSTUVWXYZABCDE"

当然,我没有字母表作为迭代范围,这只是小规模的示例,对于我的用例来说失败了。

    *
  • (splat)操作员并不懒惰
  • map
  • 不懒
    
    
  • 通过更多的谷歌搜索和实验,我得出了以下结构:

# 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

这对我来说确实过于复杂,也许有人有更好的主意?

感谢您的宝贵时间,

泽维尔。


ruby iteration range lazy-evaluation
1个回答
0
投票
如何惰性连接 Ruby 范围?

您可以通过

+

 连接枚举器。范围不是枚举器,但您可以通过 
each 检索一个范围,例如:
enum = (-3..0).each + (1..).each

组合的枚举器将迭代每个串联的枚举器:

enum.take(10) #=> [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6]

我有一个非常大的范围来迭代并找到满足特定约束的第一个元素

Ruby 有一个专用方法

find

 来执行此操作。它迭代集合并返回第一个元素(不再迭代),例如
enum.find { |i| i > 5 } #=> 6

© www.soinside.com 2019 - 2024. All rights reserved.