3

确定是否定义的最简洁方法是什么,如果或为零@hash[:key1][:key2]则不会引发错误?@hash@hash[:key1]

defined?(@hash[:key1][:key2])如果存在则返回True @hash[:key1](不判断是否:key2定义)

4

6 回答 6

6

使用 ActiveSupport (Rails) 或 Backports 时,您可以使用try

@hash[:key1].try(:fetch, :key2)

你甚至可以@hash处理nil

@hash.try(:fetch, :key1).try(:fetch, :key2)

如果您想@hash始终为丢失的键返回哈希:

@hash = Hash.new { |h,k| h[k] = {} }
@hash[:foo] # => {}

你也可以定义这个递归:

def recursive_hash
  Hash.new { |h,k| h[k] = recursive_hash }
end

@hash = recursive_hash
@hash[:foo][:bar][:blah] = 10
@hash # => {:foo => {:bar => {:blah => 10}}}

但要回答你的问题:

module HasNestedKey
  Hash.send(:include, self)
  def has_nested_key?(*args)
    return false unless sub = self[args.shift]
    return true if args.empty?
    sub.respond_to?(:has_nested_key?) and sub.has_nested_key?(*args)
  end
end

@hash.has_nested_key? :key1, :key2
于 2010-07-29T04:36:01.147 回答
4

也许我错过了一些东西,但如果你关心的只是简洁......为什么不:

@hash && @hash[:key1] && @hash[:key1][:key2]

或者如果你想保存几个字符

@hash && (h = @hash[:key1]) && h[:key2]

如果其中任何部分失败,则返回,nil否则返回与:key2or关联的值true

defined?即使不存在也返回 true的原因:key2是因为它只是检查您引用的对象是否存在,在这种情况下,该方法是散列上确实存在[]的方法的别名,但如果返回 nil ,没有 fetch 方法,它会返回。话虽如此,如果您必须深入研究嵌入式哈希,那么在某些时候调用会变得更有效率:fetch@hash[:key1]nilniln

defined?(@hash[:key1][:key2][:key3]) && @hash[:key1][:key2][:key3]
于 2010-07-29T04:52:26.667 回答
2

使用哈希#fetch

您可以使用默认为的Hash#fetch{}方法,这样has_key?即使第一级键不存在也可以安全调用。例如

!hash.nil? && hash.fetch(key1, {}).has_key?(key2)

选择

或者,您可以使用条件运算符,例如

!hash.nil? && (hash.has_key?(key1) ? hash[key1].has_key?(key2) : false)

即如果hash没有密钥key1,则返回false而不寻找第二级密钥。如果确实有,key1则返回检查key1's值的结果key2

此外,如果您想在调用它之前检查该hash[key1]'s值是否有方法:has_key?

!hash.nil? && (hash.has_key?(key1) ? hash[key1].respond_to?(:has_key?) &&
   hash[key1].has_key?(key2) : false)
于 2010-07-28T18:57:02.153 回答
0
@hash[:key1].has_key? :key2
于 2010-07-28T18:13:44.427 回答
0

如果您不关心从 中区分不存在@hash[:key1][:key2](在 3 个级别中的任何一个级别)@hash[:key1][:key2] == nil,那么这非常干净并且适用于任何深度:

[:key1,:key2].inject(hash){|h,k| h && h[k]}

如果您想nil被视为现有,请改用:

(hash[:key1].has_key?(:key2) rescue false)
于 2010-07-28T23:54:58.800 回答
0

我刚刚发现的另一种选择是使用seek方法扩展 Hash。技术来自Corey O'Daniel

将其粘贴在初始化程序中:

class Hash
  def seek(*_keys_)
    last_level    = self
    sought_value  = nil

    _keys_.each_with_index do |_key_, _idx_|
      if last_level.is_a?(Hash) && last_level.has_key?(_key_)
        if _idx_ + 1 == _keys_.length
          sought_value = last_level[_key_]
        else                   
          last_level = last_level[_key_]
        end
      else 
        break
      end
    end

    sought_value
  end 
end

然后只需调用:

@key_i_need = @hash.seek :one, :two, :three

你会得到这个值,如果它不存在,你会得到 nil 。

于 2012-11-29T02:37:13.213 回答