हाश से एक कुंजी कैसे निकालें और शेष हैश को रूबी / रेल में प्राप्त करें?


560

हाश मैं एक नई जोड़ी जोड़ने के लिए:

{:a => 1, :b => 2}.merge!({:c => 3})   #=> {:a => 1, :b => 2, :c => 3}

क्या हैश से एक कुंजी को हटाने का एक समान तरीका है?

यह काम:

{:a => 1, :b => 2}.reject! { |k| k == :a }   #=> {:b => 2}

लेकिन मुझे उम्मीद है कि कुछ ऐसा होगा:

{:a => 1, :b => 2}.delete!(:a)   #=> {:b => 2}

यह महत्वपूर्ण है कि वापसी मूल्य शेष हैश होगा, इसलिए मैं इस तरह की चीजें कर सकता था:

foo(my_hash.reject! { |k| k == my_key })

एक पंक्ति में।


1
यदि आप वास्तव में इसकी आवश्यकता है, तो आप इस कस्टम विधि को जोड़ने के लिए हैश में निर्मित (रनटाइम पर खुला) हमेशा बढ़ा सकते हैं।
dbryson

जवाबों:


750

रेल के अलावा एक / छोड़कर है! विधि है कि हटाए गए उन कुंजियों के साथ हैश लौटाता है। यदि आप पहले से ही रेल का उपयोग कर रहे हैं, तो इसका अपना संस्करण बनाने में कोई समझदारी नहीं है।

class Hash
  # Returns a hash that includes everything but the given keys.
  #   hash = { a: true, b: false, c: nil}
  #   hash.except(:c) # => { a: true, b: false}
  #   hash # => { a: true, b: false, c: nil}
  #
  # This is useful for limiting a set of parameters to everything but a few known toggles:
  #   @person.update(params[:person].except(:admin))
  def except(*keys)
    dup.except!(*keys)
  end

  # Replaces the hash without the given keys.
  #   hash = { a: true, b: false, c: nil}
  #   hash.except!(:c) # => { a: true, b: false}
  #   hash # => { a: true, b: false }
  def except!(*keys)
    keys.each { |key| delete(key) }
    self
  end
end

51
आपको पूर्ण रेल स्टैक का उपयोग करने की आवश्यकता नहीं है। आप किसी भी रूबी एप्लिकेशन में ActiveSupport शामिल कर सकते हैं।
फेरी

10
फ्राइ के जवाब में जोड़ने के लिए, आपको सभी ActiveSupport को लोड करने की भी आवश्यकता नहीं है; आप बस उन्हें फिर शामिल कर सकते हैंrequire "active_support/core_ext/hash/except"
GMA

संपादित करने में बहुत देर हो गई: मेरा मतलब था "मणि को शामिल करें" "उन्हें शामिल न करें"
जीएमए

@GMA: जब आपके पांच मिनट का संपादन समाप्त हो जाता है, तो आप किसी टिप्पणी को हमेशा कॉपी, डिलीट, संशोधित और रीपोस्ट कर सकते हैं।
इकोलॉस्टल

211

Oneliner सादा रूबी, यह केवल रूबी के साथ काम करता है> 1.9.x:

1.9.3p0 :002 > h = {:a => 1, :b => 2}
 => {:a=>1, :b=>2} 
1.9.3p0 :003 > h.tap { |hs| hs.delete(:a) }
 => {:b=>2} 

टैप विधि हमेशा उस वस्तु को लौटाती है जिस पर ...

अन्यथा यदि आपको आवश्यक है active_support/core_ext/hash(जो कि प्रत्येक रेल एप्लिकेशन में स्वचालित रूप से आवश्यक है) तो आप अपनी आवश्यकताओं के आधार पर निम्न विधियों में से एक का उपयोग कर सकते हैं:

  ~  irb
1.9.3p125 :001 > require 'active_support/core_ext/hash' => true 
1.9.3p125 :002 > h = {:a => 1, :b => 2, :c => 3}
 => {:a=>1, :b=>2, :c=>3} 
1.9.3p125 :003 > h.except(:a)
 => {:b=>2, :c=>3} 
1.9.3p125 :004 > h.slice(:a)
 => {:a=>1} 

सिवाय एक ब्लैकलिस्ट दृष्टिकोण का उपयोग करता है, इसलिए यह आर्ग के रूप में सूचीबद्ध सभी कुंजी को हटा देता है, जबकि स्लाइस में एक श्वेतसूची दृष्टिकोण का उपयोग किया जाता है, इसलिए यह उन सभी कुंजियों को हटा देता है जिन्हें तर्क के रूप में सूचीबद्ध नहीं किया गया है। वहाँ भी उन विधि ( except!और slice!) के धमाके संस्करण मौजूद हैं जो दिए गए हैश को संशोधित करते हैं, लेकिन उनका वापसी मूल्य अलग है दोनों एक हैश लौटाते हैं। इसके लिए हटाए गए कुंजियों slice!और except!निम्न कुंजियों का प्रतिनिधित्व करता है :

1.9.3p125 :011 > {:a => 1, :b => 2, :c => 3}.except!(:a)
 => {:b=>2, :c=>3} 
1.9.3p125 :012 > {:a => 1, :b => 2, :c => 3}.slice!(:a)
 => {:b=>2, :c=>3} 

18
+1 यह ध्यान देने योग्य है कि यह विधि विनाशकारी है hHash#exceptमूल हैश को संशोधित नहीं करेगा।
शुक्रिया

3
h.dup.tap { |hs| hs.delete(:a) }मूल हैश को संशोधित करने से बचने के लिए उपयोग करें ।
मैजिकोड

181

सिर्फ उपयोग क्यों नहीं:

hash.delete(key)

2
@dbryson: मैं मानता हूं कि कभी-कभी यह इसके लायक नहीं होता। मैं सिर्फ आश्चर्य है कि क्यों देखते हैं merge, merge!, delete, लेकिन कोई detele!...
Misha Moroshko

1
अगर आपको वास्तव में एक लाइनर के रूप में इसकी आवश्यकता है:foo(hash.delete(key) || hash)
बर्ट गोएथलस

13
यह रूबी परंपराओं से अधिक सुसंगत अगर होगा deleteथा नहीं इसकी पैरामीटर को संशोधित करने और अगर delete!अस्तित्व में है और इसके पैरामीटर को संशोधित किया है।
डेविड जे।

60
यह शेष हैश को प्रश्न में वर्णित के रूप में वापस नहीं करता है, यह हटाए गए कुंजी के साथ जुड़े मूल्य को वापस कर देगा।
मुदस्सिरवान

1
हटाता है कुंजी लेकिन यह भी हैश बदल देता है। जैसे कि कोई डिलीट क्यों नहीं है!, मेरा अनुमान है कि यह शब्दार्थ से किसी चीज़ को डिलीट करने का कोई मतलब नहीं है और वास्तव में इसे डिलीट नहीं करना है। hash.delete () का विरोध करते हुए hash.delete () कॉलिंग एक नो-ऑप होगा।
एग्मैटर्स

85

एक हैश से एक कुंजी को हटाने और रूबी में शेष हैश प्राप्त करने के कई तरीके हैं।

  1. .slice=> यह चयनित कुंजियों को लौटाएगा और उन्हें मूल हैश से नहीं हटाएगा। का प्रयोग करें slice!आप कुंजी स्थायी रूप से किसी और उपयोग सरल निकालना चाहते हैं slice

    2.2.2 :074 > hash = {"one"=>1, "two"=>2, "three"=>3}
     => {"one"=>1, "two"=>2, "three"=>3} 
    2.2.2 :075 > hash.slice("one","two")
     => {"one"=>1, "two"=>2} 
    2.2.2 :076 > hash
     => {"one"=>1, "two"=>2, "three"=>3} 
  2. .delete => यह मूल हैश से चयनित कुंजी को हटा देगा (यह केवल एक कुंजी को स्वीकार कर सकता है और एक से अधिक नहीं)।

    2.2.2 :094 > hash = {"one"=>1, "two"=>2, "three"=>3}
     => {"one"=>1, "two"=>2, "three"=>3} 
    2.2.2 :095 > hash.delete("one")
     => 1 
    2.2.2 :096 > hash
     => {"two"=>2, "three"=>3} 
  3. .except=> यह शेष कुंजियों को वापस कर देगा लेकिन मूल हैश से कुछ भी नहीं हटाएगा। का प्रयोग करें except!आप कुंजी स्थायी रूप से किसी और उपयोग सरल निकालना चाहते हैं except

    2.2.2 :097 > hash = {"one"=>1, "two"=>2, "three"=>3}
     => {"one"=>1, "two"=>2, "three"=>3} 
    2.2.2 :098 > hash.except("one","two")
     => {"three"=>3} 
    2.2.2 :099 > hash
     => {"one"=>1, "two"=>2, "three"=>3}         
  4. .delete_if=> यदि आपको मूल्य के आधार पर एक कुंजी निकालने की आवश्यकता है। यह स्पष्ट रूप से मूल हैश से मिलान कुंजी को हटा देगा।

    2.2.2 :115 > hash = {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1}
     => {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1} 
    2.2.2 :116 > value = 1
     => 1 
    2.2.2 :117 > hash.delete_if { |k,v| v == value }
     => {"two"=>2, "three"=>3} 
    2.2.2 :118 > hash
     => {"two"=>2, "three"=>3} 
  5. .compact=> इसका उपयोग nilहैश से सभी मान निकालने के लिए किया जाता है । compact!यदि आप nilमानों को स्थायी रूप से हटाना चाहते हैं तो उपयोग करें अन्यथा सरल का उपयोग करें compact

    2.2.2 :119 > hash = {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil}
     => {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil} 
    2.2.2 :120 > hash.compact
     => {"one"=>1, "two"=>2, "three"=>3}

रूबी 2.2.2 के आधार पर परिणाम।


15
sliceऔर exceptउपयोग करके जोड़े जाते हैं ActiveSupport::CoreExtensions::Hash। वे रूबी कोर का हिस्सा नहीं हैं। वे उपयोग कर सकते हैंrequire 'active_support/core_ext/hash'
Madis Nõmme

3
चूंकि रूबी 2.5 Hash#sliceमानक पुस्तकालय में है। माणिक-doc.org/core-2.5.0/Hash.html#method-i-slice Yay!
मैडिस N Madmme

38

यदि आप शुद्ध रूबी (कोई रेल) ​​का उपयोग करना चाहते हैं, तो विस्तार के तरीके नहीं बनाना चाहते हैं (हो सकता है कि आपको केवल एक या दो स्थानों पर इसकी आवश्यकता हो और तरीकों के टन के साथ नाम स्थान को प्रदूषित नहीं करना चाहते) और नहीं करना चाहते हैं स्थान पर हैश संपादित करें (जैसे, आप मेरे जैसे कार्यात्मक प्रोग्रामिंग के प्रशंसक हैं), आप 'चयन' कर सकते हैं:

>> x = {:a => 1, :b => 2, :c => 3}
=> {:a=>1, :b=>2, :c=>3}
>> x.select{|x| x != :a}
=> {:b=>2, :c=>3}
>> x.select{|x| ![:a, :b].include?(x)}
=> {:c=>3}
>> x
=> {:a=>1, :b=>2, :c=>3}

30
#in lib/core_extensions.rb
class Hash
  #pass single or array of keys, which will be removed, returning the remaining hash
  def remove!(*keys)
    keys.each{|key| self.delete(key) }
    self
  end

  #non-destructive version
  def remove(*keys)
    self.dup.remove!(*keys)
  end
end

#in config/initializers/app_environment.rb (or anywhere in config/initializers)
require 'core_extensions'

मैंने इसे सेट कर दिया है ताकि .remove हैश की एक कॉपी, हटाए गए कीज़ के साथ वापस आ जाए! हैश को ही संशोधित करता है। यह रूबी सम्मेलनों के साथ है। जैसे, सांत्वना से

>> hash = {:a => 1, :b => 2}
=> {:b=>2, :a=>1}
>> hash.remove(:a)
=> {:b=>2}
>> hash
=> {:b=>2, :a=>1}
>> hash.remove!(:a)
=> {:b=>2}
>> hash
=> {:b=>2}
>> hash.remove!(:a, :b)
=> {}

26

आप मणि except!से उपयोग कर सकते हैं facets:

>> require 'facets' # or require 'facets/hash/except'
=> true
>> {:a => 1, :b => 2}.except(:a)
=> {:b=>2}

मूल हैश नहीं बदलता है।

EDIT: जैसा कि रसेल कहते हैं, पहलुओं में कुछ छिपे हुए मुद्दे हैं और ActiveSupport के साथ पूरी तरह से एपीआई-संगत नहीं है। दूसरी तरफ ActiveSupport के रूप में पहलुओं के रूप में पूरा नहीं है। अंत में, मैं एएस का उपयोग करता हूं और किनारे के मामलों को आपके कोड में देता हूं।


बस require 'facets/hash/except'और उनका कोई "मुद्दा" नहीं है (यह निश्चित नहीं है कि वे 100% एएस एपीआई के अलावा और क्या मुद्दे होंगे)। यदि आप AS का उपयोग करके एक रेल परियोजना कर रहे हैं, तो समझ में नहीं आता है कि यदि Facets के पास बहुत छोटे पदचिह्न हैं।
ट्रांस

@trans ActiveSupport आजकल एक बहुत छोटा पदचिह्न भी है, और आपको इसके कुछ हिस्सों की आवश्यकता हो सकती है। बस पहलुओं की तरह, लेकिन इस पर कई और आँखों के साथ (इसलिए मुझे लगता है कि इसे बेहतर समीक्षा मिलती है)।
फिर से लिखा

19

बड़े पुस्तकालयों सहित बंदर पैचिंग या बेवजह के बजाय, यदि आप रूबी 2 का उपयोग कर रहे हैं, तो आप शोधन का उपयोग कर सकते हैं :

module HashExtensions
  refine Hash do
    def except!(*candidates)
      candidates.each { |candidate| delete(candidate) }
      self
    end

    def except(*candidates)
      dup.remove!(candidates)
    end
  end
end

आप इस सुविधा का उपयोग अपने कार्यक्रम के अन्य हिस्सों को प्रभावित किए बिना, या बड़े बाहरी पुस्तकालयों को शामिल करने के लिए कर सकते हैं।

class FabulousCode
  using HashExtensions

  def incredible_stuff
    delightful_hash.except(:not_fabulous_key)
  end
end

17

शुद्ध रूबी में:

{:a => 1, :b => 2}.tap{|x| x.delete(:a)}   # => {:b=>2}

13

रूबी ऑन रेल्स देखें : कई हैश कीज को हटाएं

hash.delete_if{ |k,| keys_to_delete.include? k }

keys_to_delete.each {| के | बड़े डेटासेट के लिए hash.delete (k)} बहुत तेज़ है। गलत होने पर मुझे सुधारो
विग्नेश जयावेल

@VigneshJayavel, आप सही हैं लेकिन ओपी चाहते थे कि हैश लौटाया जाए। eachसरणी वापस आ जाएगी।
Nakilon

3

डिलीट पेयर ऑफ हैश को डिलीट करें तो बहुत अच्छा था। मैं यह कर रही हूँ:

hash = {a: 1, b: 2, c: 3}
{b: hash.delete(:b)} # => {:b=>2}
hash  # => {:a=>1, :c=>3} 

1

यह करने के लिए एक लाइन तरीका है, लेकिन यह बहुत पठनीय नहीं है। इसके बजाय दो लाइनों का उपयोग करने की सलाह देते हैं।

use_remaining_hash_for_something(Proc.new { hash.delete(:key); hash }.call)

1
Hash#exceptऔर Hash#except!पहले से ही पर्याप्त उल्लेख किया गया है। Proc.newसंस्करण बहुत पठनीय के रूप में आप का उल्लेख है और यह भी की तुलना में अधिक जटिल नहीं है use_remaining_hash_for_something(begin hash.delete(:key); hash end)। शायद इस उत्तर को हटा दें।
माइकल कोहल

1
मेरे उत्तर को छोटा कर दिया और जो पहले ही कहा जा चुका था उसे हटा दिया। अपनी टिप्पणी के साथ मेरा जवाब रखें क्योंकि वे सवाल का जवाब देते हैं और उपयोग के लिए अच्छी सिफारिशें करते हैं।
the_minted

0

हैश में की को हटाने के कई तरीके। आप नीचे से किसी भी विधि का उपयोग कर सकते हैं

hash = {a: 1, b: 2, c: 3}
hash.except!(:a) # Will remove *a* and return HASH
hash # Output :- {b: 2, c: 3}

hash = {a: 1, b: 2, c: 3}
hash.delete(:a) # will remove *a* and return 1 if *a* not present than return nil

बहुत सारे तरीके हैं, आप यहाँ हैश के रूबी डॉक्टर पर देख सकते हैं

धन्यवाद


-12

यह भी काम करेगा: hash[hey] = nil


3
h = {: a => 1,: b => 2,: c => 3}; ज [: एक] = नहीं के बराबर; h.each {| कश्मीर, वी | put k} समान नहीं है: h = {: a => 1,: b => 2,: c => 3}; h.delete (: एक); h.each {| कश्मीर, वी | डालता है}
obaqueiro

1
एक हैश से एक कुंजी को हटाने के लिए एक हैश से एक कुंजी के मूल्य को हटाने के समान नहीं है। चूंकि इससे लोग भ्रमित हो सकते हैं, इसलिए बेहतर होगा कि इस उत्तर को हटा दिया जाए।
सेबस्टियन पाल्मा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.