如何从哈希中删除一个键,并在Ruby/Rails中获得剩余的哈希?

添加一对新的哈希,我做:

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

在一行里。

580323 次浏览

为什么不直接使用:

hash.delete(key)

hash现在是“剩余散列”;你要找的。

#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)
=> {}

你可以使用facets宝石中的except!:

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

原来的哈希值不会改变。

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

onlineer普通红宝石,它只适用于红宝石> 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(在每个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版本,它们修改给定的哈希,但它们的返回值不同,它们都返回哈希。它代表了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}

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

在纯Ruby中:

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

如果你想使用纯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}

这是一种单行的方式,但可读性不强。建议用两行代替。

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

这也可以:hash[hey] = nil

看到# EYZ0

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

你可以使用如果你在使用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

有许多方法可以从散列中删除键并在Ruby中获取剩余的散列。

  1. 它将返回所选的键,而不会从原始散列中删除它们。如果您想永久删除键,请使用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 => 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.

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

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

多种方法删除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

有很多方法,你可以在Ruby的hash# EYZ0文档中找到。

谢谢你!

Hash#except (Ruby 3.0+)

从Ruby 3.0开始,散列#除外是一个内置方法。

因此,不再需要依赖ActiveSupport或编写monkey-patches来使用它。

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

来源:

尝试except!方法。

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