Reputation: 7398
There are two arrays of hashes
actual = [{id: 1, text: "A", type: "X", state: "enabled"}, {id: 2, text: "B", type: "X", state: "enabled"}]
expected = [{text: "A", type: "X", state: "enabled"}]
I need to get the :id of all Hash not included in "expected". The comparison has to be done using three keys (text, type, state). In this case
results = [{id: 2}]
At the moment I am using this but it's very long and not performing for a big array. Is there a better way?
actuals = actuals.map{|a| a.slice(:text, :type, :state)}
expected = expected.map{|a| a.slice(:text, :type, :state)}
not_expected = actuals - expected
results = actuals.select{|actual|
not_expected.find{|n|
n[:text] == actual[:text] &&
n[:type] == actual[:type] &&
n[:state] == actual[:state]
}.present?
}
Upvotes: 3
Views: 250
Reputation: 110725
exp = expected.first
#=> {text: "A", type: "X", state: "enabled"}
actual.reject { |h| h == h.merge(exp) }.map { |h| h.slice(:id) }
#=> [{:id=>2}]
Hashes in actual
are rejected if they are unaffected when merged with exp
, meaning that the hashes being merged have the same values for all the keys in exp
. Each remaining hash h
in actual
is then mapped to { id: h[:id] }
, using Hash#slice.
One advantage of this approach is that the code need not be changed if exp
is changed to a hash having different keys.
Upvotes: 3
Reputation: 1093
actual = [{id: 1, text: "A", type: "X", state: "enabled"}, {id: 2, text: "B", type: "X", state: "enabled"}]
expected = [{text: "A", type: "X", state: "enabled"}]
comparable_expected = expected.map { |e| e.slice(:text, :type, :state) }
results = actual.select do |a|
not comparable_expected.include? a.slice(:text, :type, :state)
end
resulting_ids = results.map(&:id)
Upvotes: 5