从哈希循环中跳过密钥

时间:2018-08-08 07:51:50

标签: ruby-on-rails ruby hash

我正在对哈希值执行操作,可以说:

hash = { a: true, b: false, c: nil }

我正在each上执行hash循环,但是我想跳过键bc。我不想从hash中删除它们。

我尝试过:

hash = { a: true, b: false, c: nil}
hash.except(:c)
{ a: true, b: false, c: nil}

但是它不起作用。我正在使用ruby 2.4.2

3 个答案:

答案 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