Ruby:根据所需的键将一个哈希分成两个

Mat*_*chu 22 ruby hash

我希望这个问题有一个非常简单的答案.我可以想办法用无聊的,恼人的循环来做,但我希望有一个更优雅的解决方案.

如果我有以下两个变量:

hash = {:a => 1, :b => 2, :c => 3, :d => 4}
keyset = [:a, :c]
Run Code Online (Sandbox Code Playgroud)

如何以最简单的方式获得以下两个哈希值?

hash1 = {:a => 1, :c => 3}
hash2 = {:b => 3, :d => 4}
Run Code Online (Sandbox Code Playgroud)

如果示例没有明确我的目标,实质上,我想要的是#delete和之间的混合#delete_if- #delete返回已删除的值,而#delete_if允许我批量删除.我更喜欢批量删除的方法,并返回已删除的值 - 或等效的东西.

谢谢!

Rya*_*ary 33

尝试使用Hash#slice和/或使用Active Support Hash#except.爆炸方法也存在:

$ 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}
Run Code Online (Sandbox Code Playgroud)


Mar*_*k W 12

new_hash = {}
keyset.each {|i| new_hash[i] = hash.delete(i)}
Run Code Online (Sandbox Code Playgroud)

这似乎是为我做的,没有提出额外的要求


小智 12

hash = { a: 1, b: 2, c: 3, d: 4 }
keyset = [:a, :c]

left, right = hash.partition {|k,v| keyset.include? k }
Run Code Online (Sandbox Code Playgroud)

这左右为数组阵列; 转回哈希:

left = Hash[left]
right = Hash[right]

puts "left=#{left.inspect}"
puts "right=#{right.inspect}"
Run Code Online (Sandbox Code Playgroud)

  • 看起来像Ruby的设计缺陷是`.partition`本身不是答案; 鉴于`Hash #select`和`Hash#reject`返回哈希值,`Hash#partition`返回两个哈希值的数组是有意义的.但也许我错过了一些东西. (4认同)
  • 如果你想得到一个哈希(在Ruby 2.0+中)你可以做`left,right = hash.partition {| k,v | keyset.include?(k)} .map(&:to_h)` (3认同)

D-R*_*ock 6

通过 Rails/Active Support,您可以使用以下extract!方法:

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}
Run Code Online (Sandbox Code Playgroud)