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'}]
标准键是a和b 。 所以当我得到类似的结果时
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))
所以你真的应该自己尝试一下,因为我基本上是为你解决的。
一般方法是:
- 对于array1中的每一次
- 检查以查看array2中的相同值是否具有相同值的任何键和值
- 如果他们这样做,删除它
你可能会得到类似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 } }