有两个哈希数组,我想根据某些键从两个数组中删除'common'元素。例如:
array1-array2 (don't have to overwrite '-' if there's better approach)
标准键是 a 和 b 。所以当我得到像
这样的结果时CREATE TABLE CASEDETAIL ( CaseNumber, CaseType ) AS
SELECT 1, 'RelevantToThisQuestion' FROM DUAL
UNION ALL SELECT 2, 'RelevantToThisQuestion' FROM DUAL
UNION ALL SELECT 3, 'RelevantToThisQuestion' FROM DUAL
UNION ALL SELECT 4, 'NotRelevantToThisQuestion' FROM DUAL;
CREATE TABLE LINKEDPEOPLE ( CaseNumber, RelationshipType, LinkedPerson ) AS
SELECT 1, 'Owner', 123 FROM DUAL
UNION ALL SELECT 1, 'Agent', 124 FROM DUAL
UNION ALL SELECT 1, 'Contact', 125 FROM DUAL
UNION ALL SELECT 2, 'Owner', 126 FROM DUAL
UNION ALL SELECT 2, 'Agent', 127 FROM DUAL
UNION ALL SELECT 2, 'Contact', 128 FROM DUAL
UNION ALL SELECT 3, 'Owner', 129 FROM DUAL
UNION ALL SELECT 3, 'Agent', 130 FROM DUAL
UNION ALL SELECT 3, 'Contact', 131 FROM DUAL;
CREATE TABLE LOCATION ( LinkedPerson, Country ) AS
SELECT 123, 'AU' FROM DUAL
UNION ALL SELECT 124, 'UK' FROM DUAL
UNION ALL SELECT 125, 'UK' FROM DUAL
UNION ALL SELECT 126, 'US' FROM DUAL
UNION ALL SELECT 127, 'US' FROM DUAL
UNION ALL SELECT 128, 'UK' FROM DUAL
UNION ALL SELECT 129, 'UK' FROM DUAL
UNION ALL SELECT 130, 'AU' FROM DUAL
UNION ALL SELECT 131, 'UK' FROM DUAL;
它会期望得到
[{a:'4',b:'5',c:'6'}]
我们正在使用a和b作为比较标准。它将擦除第二个元素,因为对于array1.last和array2.last,a的值是不同的。
答案 0 :(得分:8)
据我了解,您将获得两个哈希数组和一组键。对于所有指定的键,您希望拒绝第一个数组的所有元素(哈希),其值与第二个数组的任何元素(哈希值)匹配。你可以这样做。
<强>代码强>
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
创建了一个集合(而不是数组),以加快该行中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)
#=> #<Enumerator: [{:a=>"1", :b=>"2", :c=>"10"}, {:a=>"3", :b=>"5", :c=>"6"}]
# #:each_with_object(#<Set: {}>)>
传递e0
的第一个元素并执行块计算。
h,s = e0.next
#=> [{:a=>"1", :b=>"2", :c=>"10"}, #<Set: {}>]
h #=> {:a=>"1", :b=>"2", :c=>"10"}
s #=> #<Set: {}>
(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"] => #<Set: {["1", "2"]}>
将e0
的第二个(最后一个)元素传递给块:
h,s = e0.next
#=> [{:a=>"3", :b=>"5", :c=>"6"}, #<Set: {["1", "2"]}>]
(keys-h.keys).empty?
#=> true
所以计算:
s << h.values_at(*keys)
#=> #<Set: {["1", "2"], ["3", "5"]}>
set2
#=> #<Set: {["1", "2"], ["3", "5"]}>
拒绝来自array1
的元素
我们现在遍历array1
,拒绝块评估为true
的元素。
e1 = array1.reject
#=> #<Enumerator: [{:a=>"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 :(得分:1)
所以你真的应该自己尝试一下,因为我基本上是为你解决的。
一般方法是:
您最终可能会遇到类似array1.each_with_index { |h, i| h.delete_if {|k,v| array2[i].has_key?(k) && array2[i][k] == v } }