【问题标题】:Elegantly handling blank values in a nested hash [duplicate]优雅地处理嵌套哈希中的空白值[重复]
【发布时间】:2012-05-08 16:18:10
【问题描述】:

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

我有一个 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] 可能存在也可能不存在
  • 如果存在,它可能为空,也可能不为空。

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    #fetch是你的朋友:

    my_hash.fetch(:parent, {})[:child].blank?
    

    【讨论】:

    • 请注意,如果:parent 键不存在,这将引发异常。
    • @AndrewMarshall 不,不会。阅读 fetch 的作用。
    • 抱歉,这里没有看到第二个参数。不过,如果没有,它会的。
    • 正确 :) 这就是 fetch 有用的原因。如果元素不存在,它允许您指定默认值。我经常使用它。
    • 为什么不呢? my_hash.fetch(:parent, {}).fetch(:child, {}).fetch(:other)。显然它会变得笨拙,但我认为这会建议重新考虑设计......
    【解决方案2】:

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

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

    【讨论】:

    • 该死 - 你是对的。我确实尝试过搜索,但找不到任何相关的内容。我已经投票关闭。非常感谢。 :-)
    【解决方案3】:

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

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

    另外,调用哈希 myarray 有点误导。

    【讨论】:

      【解决方案4】:

      怎么样

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

      ?

      【讨论】:

        【解决方案5】:

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

        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?
          # ...
        

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-09-15
            • 2010-12-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-22
            • 1970-01-01
            • 2013-12-06
            相关资源
            最近更新 更多