ruby比较两个哈希数组,某些键

有两个哈希数组,我想根据某些键从两个数组中删除’common’元素。 例如:

array1 = [{a: '1', b:'2', c:'3'}, {a: '4', b: '5', c:'6'}] array2 = [{a: '1', b:'2', c:'10'}, {a: '3', b: '5', c:'6'}] 

标准键是ab 。 所以当我得到类似的结果时

 array1-array2 (don't have to overwrite '-' if there's better approach) 

它会期望得到[{a:’4’,b:’5’,c:’6′}]正弦我们使用a和b作为比较标准。 它将擦除第二个元素,因为array1.last和array2.last的a值不同。

据我所知,您将获得两个哈希数组和一组键。 对于所有指定的键,您希望拒绝第一个数组的所有元素(哈希),其值与第二个数组的任何元素(哈希值)匹配。 你可以这样做。

 require 'set' def reject_partial_dups(array1, array2, keys) set2 = array2.each_with_object(Set.new) do |h,s| s << h.values_at(*keys) if (keys-h.keys).empty? end array1.reject do |h| (keys-h.keys).empty? && set2.include?(h.values_at(*keys)) end end 

这条线:

 (keys-h.keys).empty? && set2.include?(h.values_at(*keys)) 

可以简化为:

 set2.include?(h.values_at(*keys)) 

如果array1的元素(散列)中的键值都不是nil 。 我从array2创建了一个set(而不是一个数组),以加快该行中h.values_at(*keys)的查找速度。

 keys = [:a, :b] array1 = [{a: '1', b:'2', c:'3'}, {a: '4', b: '5', c:'6'}, {a: 1, c: 4}] array2 = [{a: '1', b:'2', c:'10'}, {a: '3', b: '5', c:'6'}] reject_partial_dups(array1, array2, keys) #=> [{:a=>"4", :b=>"5", :c=>"6"}, {:a=>1, :c=>4}] 

说明

首先创建set2

 e0 = array2.each_with_object(Set.new) #=> #"1", :b=>"2", :c=>"10"}, {:a=>"3", :b=>"5", :c=>"6"}] # #:each_with_object(#)> 

传递e0的第一个元素并执行块计算。

 h,s = e0.next #=> [{:a=>"1", :b=>"2", :c=>"10"}, #] h #=> {:a=>"1", :b=>"2", :c=>"10"} s #=> # (keys-h.keys).empty? #=> ([:a,:b]-[:a,:b,:c]).empty? => [].empty? => true 

所以计算:

 s << h.values_at(*keys) #=> s << {:a=>"1", :b=>"2", :c=>"10"}.values_at(*[:a,:b] } #=> s << ["1","2"] => # 

e0的第二个(最后一个)元素传递给块:

 h,s = e0.next #=> [{:a=>"3", :b=>"5", :c=>"6"}, #] (keys-h.keys).empty? #=> true 

所以计算:

 s << h.values_at(*keys) #=> # set2 #=> # 

拒绝来自array1元素

我们现在遍历array1 ,拒绝块评估为true元素。

 e1 = array1.reject #=> #"1", :b=>"2", :c=>"3"}, # {:a=>"4", :b=>"5", :c=>"6"}, {:a=>1, :c=>4}]:reject> 

e1的第一个元素传递给块:

 h = e1.next #=> {:a=>"1", :b=>"2", :c=>"3"} a = (keys-h.keys).empty? #=> ([:a,:b]-[:a,:b,:c]).empty? => true b = set2.include?(h.values_at(*keys)) #=> set2.include?(["1","2"] => true a && b #=> true 

所以e1的第一个元素被拒绝了。 下一个:

  h = e1.next #=> {:a=>"4", :b=>"5", :c=>"6"} a = (keys-h.keys).empty? #=> true b = set2.include?(h.values_at(*keys)) #=> set2.include?(["4","5"] => false a && b #=> false 

所以e1的第二个元素不被拒绝。 最后:

 h = e1.next #=> {:a=>1, :c=>4} a = (keys-h.keys).empty? #=> ([:a,:c]-[:a,:b]).empty? => [:c].empty? => false 

所以返回true(意味着e1的最后一个元素不被拒绝),因为不需要计算:

  b = set2.include?(h.values_at(*keys)) 

所以你真的应该自己尝试一下,因为我基本上是为你解决的。

一般方法是:

  1. 对于array1中的每一次
  2. 检查以查看array2中的相同值是否具有相同值的任何键和值
  3. 如果他们这样做,删除它

你可能会得到类似array1.each_with_index { |h, i| h.delete_if {|k,v| array2[i].has_key?(k) && array2[i][k] == v } } array1.each_with_index { |h, i| h.delete_if {|k,v| array2[i].has_key?(k) && array2[i][k] == v } }