Ruby: split one hash into two based on desired keys
Solution 1
Try Active Support with Hash#slice
and/or Hash#except
. The bang methods also exist:
$ irb
>> require 'active_support/core_ext'
=> true
>> hash = {:a => 1, :b => 2, :c => 3, :d => 4}
=> {:a=>1, :d=>4, :b=>2, :c=>3}
>> keyset = [:a, :c]
=> [:a, :c]
>> remainders = hash.slice!(*keyset)
=> {:d=>4, :b=>2}
>> remainders
=> {:d=>4, :b=>2}
>> hash
=> {:a=>1, :c=>3}
Solution 2
hash = { a: 1, b: 2, c: 3, d: 4 }
keyset = [:a, :c]
left, right = hash.partition {|k,v| keyset.include? k }
This leaves left and right as arrays of arrays; turn back into hash:
left = Hash[left]
right = Hash[right]
puts "left=#{left.inspect}"
puts "right=#{right.inspect}"
Solution 3
new_hash = {}
keyset.each {|i| new_hash[i] = hash.delete(i)}
That seemed to do it for me, without pulling in extra requirements
Solution 4
With Rails/Active Support you can use the extract!
method:
hash = {:a => 1, :b => 2, :c => 3, :d => 4}
keyset = [:a, :c]
hash2 = hash.extract! *keyset
>> {:a=>1, :c=>3}
hash
>> {:b=>2, :d=>4}
Related videos on Youtube
Comments
-
Matchu about 4 years
I'm hoping this question has a very simple answer. I can think of ways to do with with boring, annoying looping, but I'm hoping there's a more elegant solution.
If I have the following two variables:
hash = {:a => 1, :b => 2, :c => 3, :d => 4} keyset = [:a, :c]
How can I get the following two hashes in the simplest way possible?
hash1 = {:a => 1, :c => 3} hash2 = {:b => 3, :d => 4}
If the example doesn't make my goal clear, in essence, what I want is a hybrid between
#delete
and#delete_if
-#delete
returns the deleted value, whereas#delete_if
allows me to delete in bulk. I would prefer a way to delete in bulk, and have the deleted values returned - or something equivalent.Thanks!