问题
I have got such hash of hashes
params = {collection_permissions_attributes: {'0' => {:collection_id => '1'},
'2' => {:collection_id => '1'},
'3' => {:collection_id => '4'}}}
How can I remove completely from collection_permissions_attributes
item which hash contains duplicated value? So from hash above I would like to have:
params = { collection_permissions_attributes: {'0' => {:collection_id => '1'},
'3' => {:collection_id => '4'}}}
Thanks in advance!
回答1:
Here's another way, but it requires Ruby 1.9+, as it depends on the order of the hash's elements.
Code
newams = {collection: ams[:collection].sort.reverse.to_h.invert.invert}
#=> {:collection=>{"3"=>{:collection_id=>"4"}, "0"=>{:collection_id=>"1"}}}
If for some reason it is desired that the hash elements be in key order, that can be achieved by adding a few more operations, as explained at the end of the "explanation" section.
Explanation
ams = {collection: {'0' => {:collection_id => '1'},
'2' => {:collection_id => '1'},
'3' => {:collection_id => '4'}}}
First, reorder the hash elements in descending key order, so that when two or more elements have the same value, only the element having the smallest key value will be kept. To do this and then reconstitute the hash, three steps are required:
a = ams[:collection].sort
#=> [["0", {:collection_id=>"1"}], ["2", {:collection_id=>"1"}],
# ["3", {:collection_id=>"4"}]]
b = a.reverse
#=> [["3", {:collection_id=>"4"}], ["2", {:collection_id=>"1"}],
# ["0", {:collection_id=>"1"}]]
c = b.to_h
#=> {"3"=>{:collection_id=>"4"}, "2"=>{:collection_id=>"1"},
# "0"=>{:collection_id=>"1"}}
Next, we invert the hash, making the keys values and the values keys. Because hashes cannot have duplicate keys, this eliminates the duplicates:
d = c.invert
#=> {{:collection_id=>"4"}=>"3", {:collection_id=>"1"}=>"0"}
Lastly, invert
back:
e = d.invert
#=> {"3"=>{:collection_id=>"4"}, "0"=>{:collection_id=>"1"}}
The hash elements can reordered in key order (should that be desired) like this:
e.to_a.reverse.to_h
#=> {"0"=>{:collection_id=>"1"}, "3"=>{:collection_id=>"4"}}
回答2:
I can think of as below :
params = { :employee =>
{collection_permissions_attributes: {'0' => {:collection_id => '1'},
'2' => {:collection_id => '1'},
'3' => {:collection_id => '4'}}}
}
hash = Hash[params[:employee][:collection_permissions_attributes].group_by do |k,v|
v[:collection_id]
end.map { |_,v| v.first }]
params[:employee][:collection_permissions_attributes] = hash
output
{:employee =>
{:collection_permissions_attributes => {
"0"=>{:collection_id=>"1"},
"3"=>{:collection_id=>"4"}
}
}
}
来源:https://stackoverflow.com/questions/22557456/remove-hash-from-hash-of-hashes-if-value-is-duplicated