嵌套哈希已定义?()

发布于 2024-09-12 01:01:37 字数 247 浏览 15 评论 0原文

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

如果@hash[:key1]存在,define?(@hash[:key1][:key2])返回True(它不判断:key2< /code> 已定义)

What's the most concise way to determine if @hash[:key1][:key2] is defined, that does not throw an error if @hash or @hash[:key1] are nil?

defined?(@hash[:key1][:key2]) returns True if @hash[:key1] exists (it does not determine whether :key2 is defined)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

后来的我们 2024-09-19 01:01:37

当使用 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

When using ActiveSupport (Rails) or Backports, you can use try:

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

You could even handle @hash being nil:

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

If you want @hash to always return a hash for a missing key:

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

You could also define this recursive:

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}}}

But to answer your question:

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
诗酒趁年少 2024-09-19 01:01:37

也许我遗漏了一些东西,但如果您关心的只是简洁......为什么不呢:

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

或者如果您想保存一些字符,

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

如果其中任何部分失败,它会返回 nil 否则它会返回与 :key2true 关联的值。

即使 :key2 不存在,define? 也会返回 true,因为它只是检查您引用的对象是否存在,在这种情况下就是方法 [] 是方法 fetch 的别名,该方法确实存在于哈希 @hash[:key1] 上,但如果返回 nil,则有nil 上没有 fetch 方法,它将返回 nil。话虽这么说,如果您必须n深入到嵌入的哈希中,在某些时候调用会变得更有效:

defined?(@hash[:key1][:key2][:key3]) && @hash[:key1][:key2][:key3]

Perhaps I am missing something, but if all you care about is concise...why not:

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

or if you want to save a few characters

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

if any part of this fails, it returns nil otherwise it returns the value associated with :key2 or true.

The reason the defined? returns true even if :key2 is not there is because it just checks whether the object you are referencing exists, which in that case is the method [] which is an alias for the method fetch which does exist on the hash @hash[:key1] but if that were to return nil, there is no fetch method on nil and it would return nil. That being said, if you had to go n deep into an embedded hash, at some point it would become more efficient to call:

defined?(@hash[:key1][:key2][:key3]) && @hash[:key1][:key2][:key3]
゛时过境迁 2024-09-19 01:01:37

使用 Hash#fetch

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

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

Alternative

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

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

,如果 hash 没有密钥 key1 则返回 false 无需寻找第二级钥匙。如果确实有 key1,则返回检查 key1 值是否有 key2 的结果。

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

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

Using Hash#fetch

You can use the Hash#fetch method with a default of {} so that it is safe to call has_key? even if the first level key doesn't exist. e.g.

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

Alternative

Alternatively you can use the conditional operator e.g.

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

i.e. if hash doesn't have key key1 then just return false without looking for the second level key. If it does have key1 then return the result of checking key1's value for key2.

Also, if you want to check that hash[key1]'s value has a has_key? method before calling it:

!hash.nil? && (hash.has_key?(key1) ? hash[key1].respond_to?(:has_key?) &&
   hash[key1].has_key?(key2) : false)
零時差 2024-09-19 01:01:37
@hash[:key1].has_key? :key2
@hash[:key1].has_key? :key2
新雨望断虹 2024-09-19 01:01:37

如果您不关心区分不存在的 @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)

If you don't care about distinguishing nonexistent @hash[:key1][:key2] (at any of 3 levels) from @hash[:key1][:key2] == nil, this is quite clean and works for any depth:

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

If you want nil to be treated as existing, use this instead:

(hash[:key1].has_key?(:key2) rescue false)
不打扰别人 2024-09-19 01:01:37

我刚刚发现的另一种选择是使用 seek 方法扩展 Hash。技术来自 科里·奥丹尼尔

将其放入初始值设定项中:

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 。

Another option, one that I just discovered, is to extend Hash with a seek method. Technique comes from Corey O'Daniel.

Stick this in an initializer:

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

Then just call:

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

You'll get the value, or nil if it doesn't exist.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文