625

ハッシュに新しいペアを追加するには、次のようにします。

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

Hash からキーを削除する同様の方法はありますか?

これは機能します:

{: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 })

一行で。

4

16 に答える 16

817

Railsにはexcept/exceptがあります!これらのキーを削除したハッシュを返すメソッド。すでに Rails を使用している場合は、独自のバージョンを作成しても意味がありません。

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
于 2012-06-19T17:03:50.327 に答える
230

Oneliner plain ruby, it works only with ruby > 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} 

Tap method always return the object on which is invoked...

Otherwise if you have required active_support/core_ext/hash (which is automatically required in every Rails application) you can use one of the following methods depending on your needs:

➜  ~  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 uses a blacklist approach, so it removes all the keys listed as args, while slice uses a whitelist approach, so it removes all keys that aren't listed as arguments. There also exist the bang version of those method (except! and slice!) which modify the given hash but their return value is different both of them return an hash. It represents the removed keys for slice! and the keys that are kept for the 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} 
于 2012-01-27T00:35:21.487 に答える
225

なぜ使用しないのですか:

hash.delete(key)

hash探している「残りのハッシュ」になりました。

于 2011-06-03T13:23:16.290 に答える
116

Ruby でハッシュからキーを削除し、残りのハッシュを取得する方法は多数あります。

  1. .slice=> 選択したキーを返し、元のハッシュから削除しません。slice!キーを永久に削除したい場合に使用し、それ以外の場合は simple を使用します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=> 選択したキーを元のハッシュから削除します (1 つのキーのみを受け入れ、複数のキーを受け入れることはできません)。

    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!キーを永久に削除したい場合に使用し、それ以外の場合は simple を使用します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!に削除したい場合に使用し、それ以外の場合は simple を使用します。nilcompact

    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}
    

Ruby 2.2.2 に基づく結果。

于 2016-08-30T15:05:36.147 に答える
39

純粋な Ruby (Rails なし) を使用したい場合、拡張メソッドを作成したくない場合 (これは 1 つか 2 つの場所でのみ必要であり、大量のメソッドで名前空間を汚染したくない場合があります)、作成したくない場合ハッシュをその場で編集する (つまり、あなたが私のような関数型プログラミングのファンなら)、「選択」できます:

>> 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}
于 2012-12-19T13:55:03.267 に答える
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 がキーを削除したハッシュのコピーを返すようにしましたが、remove! ハッシュ自体を変更します。これは、Ruby の規約に準拠しています。たとえば、コンソールから

>> 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)
=> {}
于 2011-06-03T14:42:11.283 に答える
27

宝石except!から使用できます:facets

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

元のハッシュは変更されません。

編集: Russel が言うように、ファセットにはいくつかの隠れた問題があり、ActiveSupport との完全な API 互換性はありません。一方、ActiveSupport はファセットほど完全ではありません。最後に、私は AS を使用して、コードでエッジ ケースを許可します。

于 2011-10-13T00:25:32.663 に答える
17

純粋な Ruby の場合:

{:a => 1, :b => 2}.tap{|x| x.delete(:a)}   # => {:b=>2}
于 2012-09-07T04:25:13.770 に答える
13

Ruby on Rails: 複数のハッシュ キーの削除を参照してください。

hash.delete_if{ |k,| keys_to_delete.include? k }
于 2014-04-07T04:18:19.640 に答える
3

方法を試してくださいexcept!

{:a => 1, :b => 2}.except!(:a)   #=> {:b => 2}
于 2021-04-04T17:18:06.760 に答える
-12

これも機能します:hash[hey] = nil

于 2014-02-02T19:29:10.690 に答える