你如何有效地迭代两个Enumerables的合并?

时间:2012-09-14 03:53:12

标签: ruby arrays performance

给出

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

3 个答案:

答案 0 :(得分:2)

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

[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

答案 1 :(得分:2)

如果你使用1.9,我将使用多个splats的能力:

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

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

所以[*a, *b].each {}看起来就像你想要的那样。

答案 2 :(得分:1)

通过将lambda作为块本身传递,你所拥有的东西可以变得更简洁,更简单:

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