6

我敢肯定我以前见过一个优雅的解决方案,但我找不到它:

我有一个 Rails 控制器,它可能有也可能没有以下哈希元素:

myhash[:parent_field]

在该父字段内,子元素也可以是空白的。我目前正在通过(非常丑陋的)方法进行检查:

if (!myhash[:parent_field] || !myhash[:parent_field][:child_field] || myhash[:parent_field][:child_field].blank?)

哪个有效,但我认为 - 当然 - 必须有一种更优雅的方式。只是重申:

  • myhash[:parent_field] 可能存在也可能不存在
  • 如果确实存在, myhash[:parent_field][:child_field] 可能存在也可能不存在
  • 如果存在,它可能为空白,也可能不为空白。
4

6 回答 6

9

#fetch是你的朋友:

my_hash.fetch(:parent, {})[:child].blank?
于 2012-04-28T01:29:46.773 回答
3

我要做的就是使用局部变量来减轻你的负担:

unless (p=foo[:parent]) && (c=p[:child]) && !c.blank?
  # Stuff is borked!
end

但让我们探索替代方案,为了好玩……


如果你不能改变你的数据结构(顺便说一句,那是一个哈希,而不是一个数组),那么你可以将 Ruby andand gem 与 Rails 结合使用,作为对可能是对象try的事物调用方法的惰性方式。nil


当您请求一个不存在的键时,您也可以将数据结构更改为返回空的自动激活哈希的哈希:

mine = Hash.new{ |h,k| Hash.new(&h.default_proc) }
mine[:root] = { dive:42 }
p mine[:root][:dive]        #=> 42
p mine[:ohno][:blah][:whee] #=> {}
p mine[:root][:blah][:whee] #=> undefined method `[]' for nil:NilClass (NoMethodError)

但是,您必须确保层次结构中的每个对象都是这些散列之一(我明确没有对 的内容执行此操作:dive,从而导致错误)。


为了替代乐趣,您可以添加自己的神奇查找方法:

class Hash
  def divedive(*keys)
    obj = self
    keys.each do |key|
      return obj unless obj && obj.respond_to?(:[])
      obj = obj[key]
    end
    obj
  end
end

if myarray.divedive(:parent,:child).blank?
  # ...
于 2012-04-27T22:57:49.897 回答
1

这是一个常见问题,可能应该作为副本关闭

该列表中的第一个作为其他两个的重复而关闭,尽管我相信我的答案比后两个更全面地涵盖了解决此问题的技术。

于 2012-04-28T00:16:56.230 回答
0

这可能取决于您的实际需求,但 OOP 方法是将数组和散列转换为实际对象。每个对象都将管理其关系(类似于 ActiveRecord),并且知道如何获取孩子和父母。

于 2012-04-27T22:57:30.297 回答
0

由于nil.blank?is true,您可以删除中间条件并简化为:

if !myarray[:parent_field] || myarray[:parent_field][:child_field].blank?

此外,调用 Hashmyarray有点误导。

于 2012-04-27T23:50:44.297 回答
-2

怎么样

!(myarray[:parent_field][:child_field] rescue nil).blank?

?

于 2012-04-27T23:31:22.173 回答