【问题标题】:How do you iterate through an amalgamation of two Enumerables efficiently?您如何有效地迭代两个 Enumerable 的合并?
【发布时间】:2012-09-07 05:27:37
【问题描述】:

给定

a = nil # or [1,2]
b = [1,2] # or nil

您能否在不分配中间代码或创建大量样板代码的情况下迭代 ab 的串联?

# meaning do this much more efficiently
((a || []) + (b || [])).each do |thing|
  # more lines here 
  puts thing
end

这有点丑:

l = lambda{|thing| do_my_thing }
a.each{|thing| l.call(thing)} if a
b.each{|thing| l.call(thing)} if b

【问题讨论】:

    标签: ruby arrays performance


    【解决方案1】:

    如果您使用的是 1.9,我会使用多个 splats 的功能:

    a = nil
    b = [1, 2]
    [*a, *b]
    #=> [1, 2]
    
    a = [3, 4]
    b = nil
    [*a, *b]
    #=> [3, 4]
    

    所以[*a, *b].each {} 看起来和你想要的完全一样。

    【讨论】:

    • 这真的很方便,但我认为它确实会导致额外的分配
    • 确实如此,但我尽量不要让这样的考虑影响干净的代码,直到它被证明是一个瓶颈。
    • 老实说,我也更喜欢它,唯一担心的是我正在开发的 gem 在 1.8 上缺乏支持,我真的想保留它
    • 请让1.8最终死掉!自 1.9 发布以来已经有好几年了,不会再有 1.8.7 版本了,1.8.7-p330 是最后一个版本。
    • 如果你真的想保持 1.8 的支持,我会去[a, b].compact.flatten.each {} btw。
    【解决方案2】:

    通过将 lambda 作为块本身传递,可以使您拥有的内容更加简洁且不那么丑陋:

    l = lambda { |thing| do_my_thing }
    a.each(&l) if a
    b.each(&l) if b
    

    【讨论】:

      【解决方案3】:

      好吧,如果您愿意创建一个容器(即使包含的元素很大,它也应该很便宜),您可以:

      [a,b].compact.each do |e|
        e.each do
          # stuff
        end
      end
      

      您确实必须创建一个容器数组,但由于您不必复制子数组的内容(而只是处理两个数组指针),因此它应该非常快速并且在GC。

      另一种解决方案可能只是创建一个方法:

      def multi_each(*args,&block)
        args.each do |a|
          a.each(&block) if a
        end
      end
      
      multi_each(nil,[1],[2,3]) do |i|
        puts i 
      end
      # 1
      # 2
      # 3
      

      【讨论】:

      • 实际上一个多迭代似乎很好,可以制作
      • 值得注意的是 *args 被强制转换成一个数组,并且显式块传递有与之相关的性能成本 (blog.sidu.in/2007/11/ruby-blocks-gotchas.html#.UFK9uLXA9Ro) 所以第二种形式可能不会比第一种更高效。
      • 好点!我想在 c 扩展中这样做会有点矫枉过正
      • 如果你绝对必须有最高的性能,那么你想降到C,是的。但是,枚举器迭代已经在 C 中实现,使用包装数组的原始解决方案不应该真正施加太多开销。如果这还不够快,ruby-inline 可能会为您提供所需的性能,而无需编写完整的扩展。
      • 为什么不用[a, b].compact.flatten.each 而不是两个嵌套的each 调用?似乎对于 OP 的要求已经足够了。
      猜你喜欢
      • 1970-01-01
      • 2010-11-03
      • 2011-11-18
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 1970-01-01
      • 2018-02-02
      • 2022-07-05
      相关资源
      最近更新 更多