要向哈希添加新对,我这样做:
{: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 })
在一行中。
对于那些刚刚来到这里知道如何从哈希中删除键/值对的人,您可以使用:
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
为什么不直接使用:
hash.delete(key)
hash
现在是您正在寻找的"剩余哈希"。
Oneliner 普通红宝石,它仅适用于 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 方法始终返回调用的对象...
否则,如果您有必需的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}
除了使用黑名单方法,因此它会删除所有列为参数的键,而 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}
有很多方法可以从哈希中删除密钥并在 Ruby 中获取剩余的哈希。
-
.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}
-
.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}
-
.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}
-
.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}
-
.compact
=> 它用于从哈希中删除所有nil
值。如果要永久删除nil
值,请使用compact!
,否则使用简单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}
基于 Ruby 2.2.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}
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}
来源:
- 哈希#除了来自官方的 Ruby 文档。
- 链接到 PR。
- Ruby 3.0 添加了 Hash#except 和 ENV.except。
#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
gem 中的except!
:
>> require 'facets' # or require 'facets/hash/except'
=> true
>> {:a => 1, :b => 2}.except(:a)
=> {:b=>2}
原始哈希不会更改。
编辑:正如Russel所说,facets有一些隐藏的问题,并且与ActiveSupport不完全兼容API。另一方面,ActiveSupport并不像faces那样完整。最后,我会使用 AS 并让边缘情况在您的代码中。
如果您使用的是 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 中:
{:a => 1, :b => 2}.tap{|x| x.delete(:a)} # => {:b=>2}
参见 Ruby on Rails:删除多个哈希键
hash.delete_if{ |k,| keys_to_delete.include? k }
如果删除返回哈希的删除对,那就太好了。我正在这样做:
hash = {a: 1, b: 2, c: 3}
{b: hash.delete(:b)} # => {:b=>2}
hash # => {:a=>1, :c=>3}
尝试except!
方法。
{:a => 1, :b => 2}.except!(:a) #=> {:b => 2}
这是一种单行方法,但可读性不强。建议改用两行。
use_remaining_hash_for_something(Proc.new { hash.delete(:key); hash }.call)
多种删除哈希键的方法。您可以使用下面的任何方法
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 文档。
谢谢
使用 delete
、 except
或 except!
sample_hash = {hey: 'hey', hello: 'hello'}
删除:
sample_hash.delete(:hey)
=> 'hey'
sample_hash
=> {hello: 'hello'}
返回键的值并删除原始对象中的键,如果没有这样的键,则返回 nil
除了:
sample_hash.except(:hey)
=> {hello: 'hello'}
sample_hash
=> {hey: 'hey', hello: 'hello'}
返回不带指定键的整个哈希,但不更新原始哈希
除了!: except!
与 except 相同,但它会像所有 bang 操作方法一样永久更改原始哈希的状态
sample_hash.except!(:hey)
=> {hello: 'hello'}
sample_hash
=> {hello: 'hello'}
我想删除键列表,并取回已删除的哈希"切片":
导轨:
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}
纯红宝石:
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}
这也行得通:hash[hey] = nil