2009-07-10 28 views
20

我希望這個問題有一個非常簡單的答案。我可以想辦法用無聊,煩人的循環做,但我希望有一個更優雅的解決方案。Ruby:根據所需的鍵將一個散列分成兩部分

如果我有以下兩個變量:

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

我怎樣才能在最簡單的方法如下兩個散列可能嗎?

hash1 = {:a => 1, :c => 3} 
hash2 = {:b => 3, :d => 4} 

如果示例不會使我的目標清晰,在本質上,我要的是#delete#delete_if之間的混合 - #delete返回刪除值,而#delete_if讓我在批量刪除。我希望有一種方法可以批量刪除,並將刪除的值返回 - 或者等價的東西。

謝謝!

回答

31

嘗試使用Hash#slice和/或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} 
+0

精彩 - 謝謝! – Matchu 2009-07-10 18:00:21

12
new_hash = {} 
keyset.each {|i| new_hash[i] = hash.delete(i)} 

這似乎爲我做的,沒有額外的需求拉動

+0

我沒有提到我在Rails上 - 因爲它似乎不相關 - 但這意味着我已經擁有Active Support。但是,還是謝謝! :) – Matchu 2009-07-10 18:01:48

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

left, right = hash.partition {|k,v| keyset.include? k } 

這使左,右爲數組的數組;變回哈希:

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

puts "left=#{left.inspect}" 
puts "right=#{right.inspect}" 
+4

這似乎是Ruby的一個設計缺陷,``.partition`本身並不是答案;假設`Hash#select`和`Hash#reject`返回哈希值,`Hash#partition`返回一個包含兩個哈希值的數組是有意義的。但也許我錯過了一些東西。 – 2015-10-23 10:04:26

0

如果你不介意的話,你可以使用https://github.com/renra/split-off-ruby外部依賴然後,你可以這樣做:

hash2 = hash.split_off!(:b, :d) 

哈希仍將包含鍵的原始值:a和:C 。上述方法已經足夠好了,但我相信,有時最好用正確的方法名錶達你的意圖。

1

使用Rails /主動支持,你可以使用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} 
相關問題