【问题标题】:Check if array element data[i][j][k] exists检查数组元素 data[i][j][k] 是否存在
【发布时间】:2014-01-23 00:16:37
【问题描述】:

我需要找出data[i][j][k] 元素是否存在,但我不知道data[i]data[i][j] 本身是否不为零。
如果我只是data[i][j][k].nil?,它会抛出undefined method [] for nil:NilClass 如果data[i] 或data[i][j] 是nil

所以,我现在正在使用

unless data[i].nil? or data[i][j].nil? or data[i][j][k].nil?
    # do something with data[i][j][k]
end

但这有点麻烦。

如果没有data[i].nil? or data[i][j].nil? or data[i][j][k].nil?,有没有其他方法可以检查data[i][j][k] 是否存在?

【问题讨论】:

  • 使用 defined? 关键字。 stackoverflow.com/questions/288715/…
  • @jigz: 不。defined? 可以告诉您是否存在类似[] 的方法,但无法预测它是否会返回nil。示例:a=[]; defined?(a[2]) #=> "method"
  • 如果您不反对使用 gem,您可以使用我的 try_to gem 并执行 try_to { a[i][j][k] } 将返回值或 nil。您甚至可以指定一个默认值,例如try_to(42) { a[i][j][k] },它将返回该值或 42。rubygems.org/gems/try_to

标签: ruby arrays


【解决方案1】:

我通常这样做:

unless (data[i][j][k] rescue false)
    # do something
end

【讨论】:

    【解决方案2】:

    这里有三种不同的选择:

    缩短

    你可以用“!”代替.nil?来稍微缩短它:

    !data[i] or !data[i][j] or !data[i][j][k]
    

    你可以通过这样做摆脱重复:

    ((data[i] || [])[j] || [])[k].nil?
    

    抽象掉这些细节

    上面的两个代码 sn-ps 都够恶心的,我可能不会在代码库中多次编写它们。

    3 维数组似乎很复杂,以至于您不应该在代码中的很多地方直接访问它。您应该考虑将其包装在具有适当名称的对象中:

    class My3DWorld
      def initialize
        # set up @data
      end
    
      # Gets the point or returns nil if it doesn't exist.
      def get_point(i, j, k)
        @data[i] && @data[i][j] && @data[i][j][k]
      end
    end
    

    改用哈希

    但是,最终,我想知道您是否真的需要 3D 阵列。实现这种数据结构的另一种更类似于 Ruby 的方式是使用散列并使用 i,j,k 坐标元组作为键。除非这是一个巨大的结构并且您需要 3D 数组的性能特征,否则我建议您在此处查看我的其他答案:

    https://stackoverflow.com/a/20600345/28128

    【讨论】:

    • 我相信你的意思是((data[i] || [])[j] || [])[k].nil?
    • 是的,我搞砸了括号。谢谢!更新
    【解决方案3】:

    新功能“改进”是一个选项:

    module ResponsiveNil
      refine NilClass do
        def [](obj)
          nil 
        end
      end
    end
    
    using ResponsiveNil
    a = [[1]]
    p a[2][3][4]  #=> nil
    

    【讨论】:

      【解决方案4】:

      你可以稍微缩短到

      if data[i] && data[i][j] && data[i][j][k]
        # do something with data[i][j][k]
      end
      

      您也可以使用“andand” gem 来编写:

      data[i].andand[j].andand[k]
      

      如果你愿意修改Array,你可以定义一个方法来启用它,例如:

      class Array
        def index_series(*args)
          result = self
          args.each do |key|
            result = result[key]
            return nil if result.nil?
          end
          result
        end
      end
      

      这会让你这样做:

      data.index_series(i, j, k)
      

      【讨论】:

      • OP 的问题是关于数组,而不是哈希。
      • @david Grayson - 谢谢。已更新。
      【解决方案5】:

      以下允许任意数量的嵌套,并允许数组元素的值可能为nil

      def element_exists?(arr, *indices)
        if arr.is_a? Array
          return true if indices.empty?
          return false if arr.size <= (i = indices.pop)
          element_exists?(arr[i], *indices)
        else
          indices.empty?
        end
      end          
      
      data = [[0,1],[2,nil]]
      
      element_exists?(data)          # => true 
      element_exists?(data, 1)       # => true 
      element_exists?(data, 2)       # => false 
      element_exists?(data, 1, 1)    # => true 
      element_exists?(data, 1, 2)    # => false 
      element_exists?(data, 1, 1, 1) # => false 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-03-24
        • 2018-09-16
        • 1970-01-01
        • 2020-01-10
        • 2021-08-27
        • 1970-01-01
        • 2015-09-02
        相关资源
        最近更新 更多