मेरे पास एक हैश है:
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}
जवाबों:
यदि आप विशेष रूप से निकाले गए तत्वों को वापस करने के लिए विधि चाहते हैं, लेकिन h1 समान बने रहने के लिए:
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2 = h1.select {|key, value| [:b, :d, :e, :f].include?(key) } # => {:b=>:B, :d=>:D}
h1 = Hash[h1.to_a - h2.to_a] # => {:a=>:A, :c=>:C}
और अगर आप हैश वर्ग में पैच करना चाहते हैं:
class Hash
def extract_subhash(*extract)
h2 = self.select{|key, value| extract.include?(key) }
self.delete_if {|key, value| extract.include?(key) }
h2
end
end
यदि आप केवल निर्दिष्ट तत्वों को हैश से हटाना चाहते हैं, तो delete_if का उपयोग करना बहुत आसान है ।
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h1.delete_if {|key, value| [:b, :d, :e, :f].include?(key) } # => {:a=>:A, :c=>:C}
h1 # => {:a=>:A, :c=>:C}
slice
या except
, का उपयोग करके ) ज्यादा साफ है
ActiveSupport
, 2.3.8 के बाद से कम से कम चार सुविधाजनक तरीके प्रदान: #slice
, #except
और उनके विनाशकारी समकक्षों: #slice!
और #except!
। उनका उल्लेख अन्य उत्तरों में किया गया था, लेकिन उन्हें एक स्थान पर रखने के लिए:
x = {a: 1, b: 2, c: 3, d: 4}
# => {:a=>1, :b=>2, :c=>3, :d=>4}
x.slice(:a, :b)
# => {:a=>1, :b=>2}
x
# => {:a=>1, :b=>2, :c=>3, :d=>4}
x.except(:a, :b)
# => {:c=>3, :d=>4}
x
# => {:a=>1, :b=>2, :c=>3, :d=>4}
धमाके के तरीकों के रिटर्न वैल्यू पर ध्यान दें। वे न केवल मौजूदा हैश दर्जी करेंगे, बल्कि एंट्री हटाए गए (नहीं रखे गए) प्रविष्टि भी लौटाएंगे। Hash#except!
सूट सबसे अच्छा उदाहरण प्रश्न में दिए गए:
x = {a: 1, b: 2, c: 3, d: 4}
# => {:a=>1, :b=>2, :c=>3, :d=>4}
x.except!(:c, :d)
# => {:a=>1, :b=>2}
x
# => {:a=>1, :b=>2}
ActiveSupport
पूरे रेल की आवश्यकता नहीं है, बहुत हल्का है। वास्तव में, बहुत सारे गैर-रेल रत्न इस पर निर्भर करते हैं, इसलिए संभवत: आपके पास यह पहले से ही Gemfile.lock में है। अपने दम पर हैश क्लास का विस्तार करने की आवश्यकता नहीं है।
x.except!(:c, :d)
(धमाके के साथ) का परिणाम होना चाहिए # => {:a=>1, :b=>2}
। यदि आप अपना उत्तर संपादित कर सकते हैं तो अच्छा है।
यदि आप रेल का उपयोग करते हैं , तो हैश # स्लाइस जाने का रास्ता है।
{:a => :A, :b => :B, :c => :C, :d => :D}.slice(:a, :c)
# => {:a => :A, :c => :C}
यदि आप रेल का उपयोग नहीं करते हैं , तो Hash # values_at मानों को उसी क्रम में लौटा देगा जैसा आपने उनसे पूछा था ताकि आप ऐसा कर सकें:
def slice(hash, *keys)
Hash[ [keys, hash.values_at(*keys)].transpose]
end
def except(hash, *keys)
desired_keys = hash.keys - keys
Hash[ [desired_keys, hash.values_at(*desired_keys)].transpose]
end
उदाहरण के लिए:
slice({foo: 'bar', 'bar' => 'foo', 2 => 'two'}, 'bar', 2)
# => {'bar' => 'foo', 2 => 'two'}
except({foo: 'bar', 'bar' => 'foo', 2 => 'two'}, 'bar', 2)
# => {:foo => 'bar'}
स्पष्टीकरण:
बाहर की {:a => 1, :b => 2, :c => 3}
हम चाहते हैं{:a => 1, :b => 2}
hash = {:a => 1, :b => 2, :c => 3}
keys = [:a, :b]
values = hash.values_at(*keys) #=> [1, 2]
transposed_matrix =[keys, values].transpose #=> [[:a, 1], [:b, 2]]
Hash[transposed_matrix] #=> {:a => 1, :b => 2}
यदि आपको लगता है कि बंदर का पेटिंग जाना रास्ता है, तो आप क्या चाहते हैं:
module MyExtension
module Hash
def slice(*keys)
::Hash[[keys, self.values_at(*keys)].transpose]
end
def except(*keys)
desired_keys = self.keys - keys
::Hash[[desired_keys, self.values_at(*desired_keys)].transpose]
end
end
end
Hash.include MyExtension::Hash
रूबी 2.5 ने हैश # स्लाइस को जोड़ा :
h = { a: 100, b: 200, c: 300 }
h.slice(:a) #=> {:a=>100}
h.slice(:b, :c, :d) #=> {:b=>200, :c=>300}
आप स्लाइस का उपयोग कर सकते हैं! (* कुंजियाँ) जो ActiveSupport के मुख्य एक्सटेंशन में उपलब्ध है
initial_hash = {:a => 1, :b => 2, :c => 3, :d => 4}
extracted_slice = initial_hash.slice!(:a, :c)
initial_hash अब होगा
{:b => 2, :d =>4}
अब निकाले जाएंगे
{:a => 1, :c =>3}
आप देख सकते हैं slice.rb in ActiveSupport 3.1.3
module HashExtensions
def subhash(*keys)
keys = keys.select { |k| key?(k) }
Hash[keys.zip(values_at(*keys))]
end
end
Hash.send(:include, HashExtensions)
{:a => :A, :b => :B, :c => :C, :d => :D}.subhash(:a) # => {:a => :A}
def subhash(*keys) select {|k,v| keys.include?(k)} end
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
keys = [:b, :d, :e, :f]
h2 = (h1.keys & keys).each_with_object({}) { |k,h| h.update(k=>h1.delete(k)) }
#=> {:b => :B, :d => :D}
h1
#=> {:a => :A, :c => :C}
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)
दोनों delete_if
और keep_if
रूबी मुख्य भाग हैं। यहां आप उस Hash
प्रकार को प्राप्त कर सकते हैं, जो आप टाइपिंग पैचिंग के बिना करना चाहते हैं ।
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2 = h1.clone
p h1.keep_if { |key| [:b, :d, :e, :f].include?(key) } # => {:b => :B, :d => :D}
p h2.delete_if { |key, value| [:b, :d, :e, :f].include?(key) } #=> {:a => :A, :c => :C}
भविष्य की जानकारी के लिए, दस्तावेज़ीकरण से नीचे दिए गए लिंक देखें:
जैसा कि दूसरों ने उल्लेख किया है, रूबी 2.5 ने हैश # स्लाइस विधि को जोड़ा।
रूब 5.2.0beta1 ने यह भी कहा कि रूबी के पुराने संस्करण का उपयोग कर रहे फ्रेमवर्क के उपयोगकर्ताओं के लिए कार्यक्षमता को कम करने के लिए हैश # स्लाइस का अपना संस्करण है। https://github.com/rails/rails/commit/01ae39660243bc5f0a986e20f9c9bff312b1b5f8
यदि किसी भी कारण से अपने स्वयं के कार्यान्वयन की तलाश है, तो यह एक अच्छा लाइनर भी है:
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_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}
नोट: यह विधि वास्तव में निकाले गए कुंजी / मान लौटाती है।
यहां एक कार्यात्मक समाधान है जो उपयोगी हो सकता है यदि आप रूबी 2.5 पर नहीं चल रहे हैं और इस मामले में कि आप एक नई विधि जोड़कर अपने हैश वर्ग को प्रदूषित नहीं करना चाहते हैं:
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"}]
स्लाइस पद्धति के अतिरिक्त, यदि आप सुभाष की चाबी को मूल हैश से अलग करना चाहते हैं, तो आप गतिशील हो सकते हैं,
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)