如何在 Ruby/Rails 中从哈希中删除密钥并获取剩余的哈希?

发布于 2024-11-13 08:57:40 字数 507 浏览 3 评论 0 原文

要向 Hash 添加新对,我这样做:

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

在一行中。

To add a new pair to Hash I do:

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

Is there a similar way to delete a key from Hash ?

This works:

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

but I would expect to have something like:

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

It is important that the returning value will be the remaining hash, so I could do things like:

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

in one line.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

小瓶盖 2024-11-20 08:57:40

对于那些刚刚来到这里了解如何从哈希中删除键/值对的人,您可以使用:
hash.delete(key)

对于其他来这里阅读完全不同内容的文字墙的人,您可以阅读此答案的其余部分:

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

For those of you who just came here to know how to delete a key/value pair from a hash, you can use:
hash.delete(key)

For the rest of you who came here to read a wall of text about something entirely different, you can read the rest of this answer:

Rails has an except/except! method that returns the hash with those keys removed. If you're already using Rails, there's no sense in creating your own version of this.

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
如歌彻婉言 2024-11-20 08:57:40

为什么不直接使用:

hash.delete(key)

hash 现在是您要查找的“剩余哈希”。

Why not just use:

hash.delete(key)

hash is now the "remaining hash" you're looking for.

姜生凉生 2024-11-20 08:57:40

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} 

Tap 方法总是返回被调用的对象...

否则,如果您需要 active_support/core_ext/hash (每个 Rails 应用程序都自动需要),您可以使用根据您的需要使用以下方法之一:

➜  ~  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 使用白名单方法,因此它会删除所有未列为参数的键。还存在这些方法的 bang 版本(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} 

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} 
薄荷港 2024-11-20 08:57:40

在 Ruby 中,有很多方法可以从哈希中删除键并获取剩余的哈希。

  1. .slice =>;它将返回选定的键,而不是将它们从原始哈希中删除。如果您想永久删除密钥,请使用 slice!,否则请使用简单的 slice

    <前><代码>2.2.2 :074>哈希 = {“一”=>1,“二”=>2,“三”=>3}
    => {“一”=>1,“二”=>2,“三”=>3}
    2.2.2:075> hash.slice("一","二")
    => {“一”=>1,“二”=>2}
    2.2.2:076>散列
    => {“一”=>1,“二”=>2,“三”=>3}

  2. .删除 =>它将从原始哈希中删除选定的键(它只能接受一个键,不能接受多个键)。

    <前><代码>2.2.2 :094>哈希 = {“一”=>1,“二”=>2,“三”=>3}
    => {“一”=>1,“二”=>2,“三”=>3}
    2.2.2:095> hash.delete("一")
    => 1
    2.2.2:096>散列
    => {“二”=>2,“三”=>3}

  3. . except =>;它将返回剩余的键,但不会从原始哈希中删除任何内容。如果您想永久删除密钥,请使用 except!,否则请使用简单的 except

    <前><代码>2.2.2 :097>哈希 = {“一”=>1,“二”=>2,“三”=>3}
    => {“一”=>1,“二”=>2,“三”=>3}
    2.2.2:098> hash. except("一","二")
    => {“三”=>3}
    2.2.2:099>散列
    => {“一”=>1,“二”=>2,“三”=>3}

  4. .delete_if =>;如果您需要根据值删除键。显然,它会从原始哈希中删除匹配的键。

    <前><代码>2.2.2 :115>哈希= {“一”=> 1,“二”=> 2,“三”=> 3,“one_again”=> 1}
    => {“一”=>1、“二”=>2、“三”=>3、“one_again”=>1}
    2.2.2:116>值 = 1
    => 1
    2.2.2:117> hash.delete_if { |k,v| v == 值 }
    => {“二”=>2,“三”=>3}
    2.2.2:118>散列
    => {“二”=>2,“三”=>3}

  5. .compact =>;它用于从哈希中删除所有 nil 值。如果您想永久删除 nil 值,请使用 compact!,否则请使用简单的 compact

    <前><代码>2.2.2 :119> hash = {“一”=>1,“二”=>2,“三”=>3,“无”=>nil,“no_value”=>nil}
    => {“一”=>1,“二”=>2,“三”=>3,“无”=>nil,“no_value”=>nil}
    2.2.2:120>哈希紧凑型
    => {“一”=>1,“二”=>2,“三”=>3}

结果基于 Ruby 2.2.2。

There are many ways to remove a key from a hash and get the remaining hash in Ruby.

  1. .slice => It will return selected keys and not delete them from the original hash. Use slice! if you want to remove the keys permanently else use 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 => It will delete the selected keys from the original hash(it can accept only one key and not more than one).

    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 => It will return the remaining keys but not delete anything from the original hash. Use except! if you want to remove the keys permanently else use 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 => In case you need to remove a key based on a value. It will obviously remove the matching keys from the original hash.

    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 => It is used to remove all nil values from the hash. Use compact! if you want to remove the nil values permanently else use simple 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}
    

Results based on Ruby 2.2.2.

只是在用心讲痛 2024-11-20 08:57:40

如果你想使用纯 Ruby(没有 Rails),不想创建扩展方法(也许你只在一两个地方需要这个,并且不想用大量方法污染命名空间)并且不想就地编辑哈希(即,您像我一样喜欢函数式编程),您可以“选择”:

>> 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}

If you want to use pure Ruby (no Rails), don't want to create extension methods (maybe you need this only in one or two places and don't want to pollute namespace with tons of methods) and don't want to edit hash in place (i.e., you're fan of functional programming like me), you can 'select':

>> 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}
×纯※雪 2024-11-20 08:57:40

Hash#except (Ruby 3.0+)

从 Ruby 3.0 开始,Hash# except 是一个内置方法。

因此,不再需要依赖 ActiveSupport 或编写猴子补丁来使用它。

h = { a: 1, b: 2, c: 3 }
p h.except(:a) #=> {:b=>2, :c=>3}

来源:

Hash#except (Ruby 3.0+)

Starting from Ruby 3.0, Hash#except is a build-in method.

As a result, there is no more need to depend on ActiveSupport or write monkey-patches in order to use it.

h = { a: 1, b: 2, c: 3 }
p h.except(:a) #=> {:b=>2, :c=>3}

Sources:

嘴硬脾气大 2024-11-20 08:57:40
#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)
=> {}
#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'

I've set this up so that .remove returns a copy of the hash with the keys removed, while remove! modifies the hash itself. This is in keeping with ruby conventions. eg, from the console

>> 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)
=> {}
稍尽春風 2024-11-20 08:57:40

您可以使用 facets gem 中的 except!

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

原始哈希值不会改变。

编辑:正如 Russel 所说,facets 有一些隐藏的问题,并且与 ActiveSupport 的 API 不完全兼容。另一方面,ActiveSupport 并不像方面那么完整。最后,我会使用 AS 并让边缘情况出现在您的代码中。

You can use except! from the facets gem:

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

The original hash does not change.

EDIT: as Russel says, facets has some hidden issues and is not completely API-compatible with ActiveSupport. On the other side ActiveSupport is not as complete as facets. In the end, I'd use AS and let the edge cases in your code.

傲娇萝莉攻 2024-11-20 08:57:40

您可以使用 如果您使用 Ruby 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

Instead of monkey patching or needlessly including large libraries, you can use refinements if you are using Ruby 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

You can use this feature without affecting other parts of your program, or having to include large external libraries.

class FabulousCode
  using HashExtensions

  def incredible_stuff
    delightful_hash.except(:not_fabulous_key)
  end
end
因为看清所以看轻 2024-11-20 08:57:40

在纯红宝石中:

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

in pure Ruby:

{:a => 1, :b => 2}.tap{|x| x.delete(:a)}   # => {:b=>2}
半暖夏伤 2024-11-20 08:57:40

请参阅 Ruby on Rails:删除多个哈希键

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

See Ruby on Rails: Delete multiple hash keys

hash.delete_if{ |k,| keys_to_delete.include? k }
陌伤ぢ 2024-11-20 08:57:40

使用 delete except except!

sample_hash = {hey: 'hey', hello: 'hello'}

删除:

sample_hash.delete(:hey)
=> 'hey'

sample_hash
=> {hello: 'hello'}

返回键的值并删除原对象中的键,如果没有该键则返回nil

except:

sample_hash.except(:hey)
=> {hello: 'hello'}

sample_hash
=> {hey: 'hey', hello: 'hello'}

返回不包含指定键的整个散列,但不更新原始散列

except!:
except! 与 except 相同,但它像所有 bang 操作方法一样永久更改原始哈希的状态

sample_hash.except!(:hey)
=> {hello: 'hello'}

sample_hash
=> {hello: 'hello'}

Use delete, except, or except!

sample_hash = {hey: 'hey', hello: 'hello'}

Delete:

sample_hash.delete(:hey)
=> 'hey'

sample_hash
=> {hello: 'hello'}

Returns value of the key and deletes the key in the original object, returns nil if no such key

Except:

sample_hash.except(:hey)
=> {hello: 'hello'}

sample_hash
=> {hey: 'hey', hello: 'hello'}

Returns the entire hash without the specified keys, but does not update the original hash

Except!:
except! is the same as except but it permanently changes the state of the original hash like all bang operated methods do

sample_hash.except!(:hey)
=> {hello: 'hello'}

sample_hash
=> {hello: 'hello'}
千年*琉璃梦 2024-11-20 08:57:40

如果删除返回哈希的删除对,那就太好了。
我正在这样做:

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

It's was great if delete return the delete pair of the hash.
I'm doing this:

hash = {a: 1, b: 2, c: 3}
{b: hash.delete(:b)} # => {:b=>2}
hash  # => {:a=>1, :c=>3} 
鹿童谣 2024-11-20 08:57:40

尝试使用 except! 方法。

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

Try the except! method.

{:a => 1, :b => 2}.except!(:a)   #=> {:b => 2}
私藏温柔 2024-11-20 08:57:40

我想删除键列表,并取回已删除的哈希“切片”:

Rails:

hash = {a: 1, b: 2, c: 3}

def delete_slice!(hash, *keys)
  hash.slice(*keys).tap { hash.except!(*keys) }
end

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

Pure Ruby:

hash = {a: 1, b: 2, c: 3}

def delete_slice!(hash, *keys)
  hash.slice(*keys).tap { keys.each{ hash.delete _1 } }
end

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

I want to delete a list of keys, and get back the deleted "slice" of the hash:

Rails:

hash = {a: 1, b: 2, c: 3}

def delete_slice!(hash, *keys)
  hash.slice(*keys).tap { hash.except!(*keys) }
end

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

Pure Ruby:

hash = {a: 1, b: 2, c: 3}

def delete_slice!(hash, *keys)
  hash.slice(*keys).tap { keys.each{ hash.delete _1 } }
end

delete_slice!(hash, :a, :b)
# => {a: 1, b: 2}
hash
# => {c: 3}
几度春秋 2024-11-20 08:57:40

这是一种单行的方法,但可读性不太好。建议使用两行代替。

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

This is a one line way to do it, but it's not very readable. Recommend using two lines instead.

use_remaining_hash_for_something(Proc.new { hash.delete(:key); hash }.call)
九歌凝 2024-11-20 08:57:40

多种方式删除Hash中的Key。
你可以使用下面的任何方法 方法

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

有很多,你可以查看 Hash 的 Ruby 文档 此处

谢谢

Multiple ways to delete Key in Hash.
you can use any Method from below

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

So many ways is there, you can look on Ruby doc of Hash here.

Thank you

清醇 2024-11-20 08:57:40

这也可以:hash[hey] = nil

This would also work: hash[hey] = nil

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文