替换数组中的元素(ruby)

时间:2011-11-23 15:48:18

标签: ruby arrays

我有2个对象数组,我想合并它们,使得结果数组将包含第一个数组中的所有元素,替换第二个数组具有相同id对象的任何元素。

  finalArr=[]
  arr1.each do |e1|
    set2Contains=false
    arr2.each do |e2|
      if(e2.id==e1.id)
        set2Contains=true
      end
    end
    if(set2Contains)
      finalArr.push(e2)
    else
      finalArr.push(e1)
    end
  end

我是红宝石的新手,但由于它是一个衬里的王者,上面看起来有点冗长。我想知道我的代码是否可以以任何方式缩短/优化?

感谢您的任何建议

4 个答案:

答案 0 :(得分:5)

你想让你的第二个数组成为ID的哈希,所以你不必每次都扫描它:

hash = Hash.new
arr2.collect{|x| hash[x.id] = x}

那么你可以继续做下去:

finalArr = arr1.map{|x| hash.has_key?(x.id) ? hash[x.id] : x }

请注意,如果您的数组可以包含nil,可能需要注意警告,在这种情况下,我假设情况并非如此。

答案 1 :(得分:1)

相同的逻辑,但精炼的代码:

final_arr=[]
arr1.each do |e1|
  if arr2.any? { |e2| e1.id == e2.id }
    final_arr << e2
  else
    final_arr << e1
  end
end

更简洁

final_arr=[]
arr1.each do |e1|
  final_arr << arr2.any? { |e2| e1.id == e2.id } ? e2 : e1
end

答案 2 :(得分:1)

既然你提到过单行,那么这是一个功能性的:

merged = Hash[ a1.map{|o| [o.id,o]} ].merge(Hash[ a2.map{|o| [o.id,o]} ]).values

这会将两个数组转换为id键入的哈希值,合并它们(来自a2的值会覆盖a1中的值),然后只提取值。

如果您要对这些对象进行大量类似集合的工作,我建议您在其上定义eql?hash方法来比较它们的id值,然后只使用内置的Ruby Set类:

require 'set'

Foo = Struct.new(:id,:name) do
  def eql?(o2)
    id==o2.id
  end
  def hash
    id.hash
  end
end

a1 = Set[ Foo.new(1,"Phrogz"), Foo.new(17,"Cat")   ]
a2 = Set[ Foo.new(42,"Arthur"), Foo.new(1,"Gavin") ]

all = a1 + a2
all.each{ |foo| puts foo }
#=> #<struct Foo id=1, name="Phrogz">
#=> #<struct Foo id=17, name="Cat">
#=> #<struct Foo id=42, name="Arthur">

答案 3 :(得分:1)

在ruby 1.9中,它很简单:

(a|b).uniq{|x| x[:id]}

将数组放入您不想先替换的值。