如何从 Hash 中删除一个键并在 Ruby/Rails 中获取剩余的哈希?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6227600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to remove a key from Hash and get the remaining hash in Ruby/Rails?
提问by Misha Moroshko
To add a new pair to Hash I do:
要向 Hash 添加新对,我会执行以下操作:
{:a => 1, :b => 2}.merge!({:c => 3}) #=> {:a => 1, :b => 2, :c => 3}
Is there a similar way to delete a key from Hash ?
有没有类似的方法可以从 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.
在一行中。
回答by Peter Brown
Rails has an except/except! methodthat returns the hash with those keys removed. If you're already using Rails, there's no sense in creating your own version of this.
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
回答by Fabio
Oneliner plain ruby, it works only with ruby > 1.9.x:
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}
Tapmethod always return the object on which is invoked...
Tap方法总是返回被调用的对象...
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:
否则,如果您需要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}
exceptuses a blacklist approach, so it removes all the keys listed as args, while sliceuses 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!:
except使用黑名单方法,因此它删除所有列为 args 的键,而slice使用白名单方法,因此它删除所有未列为参数的键。也存在那些修改给定散列但它们的返回值不同的方法 (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}
回答by dbryson
Why not just use:
为什么不使用:
hash.delete(key)
回答by techdreams
There are many ways to remove a key from a hash and get the remaining hash in Ruby.
有很多方法可以从散列中删除键并在 Ruby 中获取剩余的散列。
.slice=> It will return selected keys and not delete them from the original hash. Useslice!if you want to remove the keys permanently else use simpleslice.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=> 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}.except=> It will return the remaining keys but not delete anything from the original hash. Useexcept!if you want to remove the keys permanently else use simpleexcept.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=> 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}.compact=> It is used to remove allnilvalues from the hash. Usecompact!if you want to remove thenilvalues permanently else use simplecompact.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}
.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从哈希中删除所有值。使用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}
Results based on Ruby 2.2.2.
结果基于 Ruby 2.2.2。
回答by Yura Taras
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':
如果你想使用纯 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}
回答by Max Williams
#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
我已经设置了它,以便 .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)
=> {}
回答by rewritten
You can use except!from the facetsgem:
您可以except!从facetsgem 中使用:
>> 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.
编辑:正如 Russel 所说,facets 有一些隐藏的问题,并且与 ActiveSupport API 不完全兼容。另一方面,ActiveSupport 不如 facet 完整。最后,我会使用 AS 并在您的代码中使用边缘情况。
回答by Mohamad
Instead of monkey patching or needlessly including large libraries, you can use refinements if you are using Ruby 2:
如果您使用的是 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
回答by gamov
in pure Ruby:
在纯红宝石中:
{:a => 1, :b => 2}.tap{|x| x.delete(:a)} # => {:b=>2}
回答by Nakilon
See Ruby on Rails: Delete multiple hash keys
hash.delete_if{ |k,| keys_to_delete.include? k }

