我有一个哈希表:
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
最佳方法如何提取这样的子哈希?
h1.extract_subhash(:b, :d, :e, :f) # => {:b => :B, :d => :D}
h1 #=> {:a => :A, :c => :C}
我有一个哈希表:
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
最佳方法如何提取这样的子哈希?
h1.extract_subhash(:b, :d, :e, :f) # => {:b => :B, :d => :D}
h1 #=> {:a => :A, :c => :C}
def slice(*keys)
keys.each_with_object(Hash.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
end unless method_defined?(:slice)
class Hash
def extract(*keys)
key_index = Hash[keys.map{ |k| [k, true] }] # depends on the size of keys
partition{ |k, v| key_index.has_key?(k) }.map{ |group| Hash[group] }
end
end
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2, h1 = h1.extract(:b, :d, :e, :f)
#select
似乎是最快的。k = 1_000_000
Benchmark.bmbm do |x|
x.report('select') { k.times { {a: 1, b: 2, c: 3}.select { |k, _v| [:a, :b].include?(k) } } }
x.report('hash transpose') { k.times { Hash[ [[:a, :b], {a: 1, b: 2, c: 3}.fetch_values(:a, :b)].transpose ] } }
x.report('slice') { k.times { {a: 1, b: 2, c: 3}.slice(:a, :b) } }
end
Rehearsal --------------------------------------------------
select 1.640000 0.010000 1.650000 ( 1.651426)
hash transpose 1.720000 0.010000 1.730000 ( 1.729950)
slice 1.740000 0.010000 1.750000 ( 1.748204)
----------------------------------------- total: 5.130000sec
user system total real
select 1.670000 0.010000 1.680000 ( 1.683415)
hash transpose 1.680000 0.010000 1.690000 ( 1.688110)
slice 1.800000 0.010000 1.810000 ( 1.816215)
module CoreExtensions
module Extractable
refine Hash do
def extract(*keys)
select { |k, _v| keys.include?(k) }
end
end
end
end
并且使用它:
using ::CoreExtensions::Extractable
{ a: 1, b: 2, c: 3 }.extract(:a, :b)
slice_hash = -> keys, hash { hash.select { |k, _v| keys.include?(k) } }.curry
然后,您甚至可以在嵌套哈希表上应用它:
my_hash = [{name: "Joe", age: 34}, {name: "Amy", age: 55}]
my_hash.map(&slice_hash.([:name]))
# => [{:name=>"Joe"}, {:name=>"Amy"}]
这段代码将你所要求的功能注入到Hash类中:
class Hash
def extract_subhash! *keys
to_keep = self.keys.to_a - keys
to_delete = Hash[self.select{|k,v| !to_keep.include? k}]
self.delete_if {|k,v| !to_keep.include? k}
to_delete
end
end
并生成您提供的结果:
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
p h1.extract_subhash!(:b, :d, :e, :f) # => {b => :B, :d => :D}
p h1 #=> {:a => :A, :c => :C}
关于切片方法的补充,如果你想从原始哈希中分离出动态子哈希键,可以这样做:
slice(*dynamic_keys) # dynamic_keys should be an array type
class Hash
def extract(*keys)
extracted_hash = {}
keys.each{|key| extracted_hash[key] = self.delete(key) if self.has_key?(key)}
extracted_hash
end
end
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2 = h1.extract(:b, :d, :e, :f)