我正在对哈希值执行操作,可以说:
hash = { a: true, b: false, c: nil }
我正在each
上执行hash
循环,但是我想跳过键b
和c
。我不想从hash
中删除它们。
我尝试过:
hash = { a: true, b: false, c: nil}
hash.except(:c)
{ a: true, b: false, c: nil}
但是它不起作用。我正在使用ruby 2.4.2
答案 0 :(得分:2)
实际上hash.except(:c)
会按预期返回{ a: true, b: false }
。由于您使用的是Rails
,因此应该可以使用。我要记录的唯一微妙的时刻是:
hash.except([:b, :c])
不起作用。您需要使用
hash.except(:b, :c)
相反。
对于一般解决方案,您需要使用splat运算符:
keys = [:b, :c]
hash.except(*keys)
答案 1 :(得分:2)
如果您仅需要在遍历哈希对时跳过它,我个人将避免使用except
,而在循环中使用更丑陋的next if key == whatever
。
在符号之间进行相等检查很便宜,这是在Ruby中可以完成的最便宜的事情,即比较两个整数或布尔值的基本等效方法。
另一方面, except
则不是,尤其是随着散列大小的增长。每次调用时,都将创建一个减去指定值的新克隆哈希。即使哈希值很小,您也不必要创建新对象。
我了解到,许多Ruby用户永远都在追求“单一代码”或绝对最短数量的代码,我本人对此感到内,,但是它需要谨记地处理表面下发生的事情,或者您正在创建效率较低的代码,而不是更多。
因此,尽管不如“漂亮”,但这会更有效:
hash.each do |k, v|
next if k == :b || k == :c
# Do stuff
end
编辑
我很好奇我所声明的内容与使用except
之间的性能差异,结果差异很大。
首先,我添加了except
的源代码,但没有安装Rails。这直接来自activesupport/lib/active_support/core_ext/hash/except.rb
的源代码。
class Hash
def except!(*keys)
keys.each { |key| delete(key) }
self
end
def except(*keys)
dup.except!(*keys)
end
end
然后我做了一些基准测试。我认为一百万个样本足以进行一次运行。
require 'benchmark'
hash = { a: true, b: false, c: nil }
count = 1_000_000
Benchmark.bm do |bm|
bm.report("except") do
count.times do
hash.except(:b, :c).each do |k, v|
# Do nothing
end
end
end
bm.report("next") do
count.times do
hash.each do |k, v|
next if k == :b || k == :c
# Do nothing
end
end
end
end
运行各种时间,包括更改为bmbm
以确认GC不会扭曲任何东西:
user system total real
except 1.282000 0.000000 1.282000 ( 1.276943)
next 0.250000 0.000000 0.250000 ( 0.246193)
平均而言,使用next
可使代码速度提高5倍以上。散列变得越大,这种差异就越大。
答案 2 :(得分:-1)
我可能只会做这样的事情
my_hash = hash.reject { |k, _| %i[a b].include?(k) }
my_hash.each do |k, v|
# Do what you need to and be free from worry about those pesky :a and :b keys
end