检查数组元素data [i] [j] [k]是否存在

时间:2014-01-05 15:57:38

标签: ruby arrays

我需要了解data[i][j][k]元素是否存在,但我不知道data[i]data[i][j]是否自己为零。
如果我只是data[i][j][k].nil?,如果data [i]或data [i] [j]为undefined method [] for nil:NilClass,则会抛出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][j][k]是否存在data[i].nil? or data[i][j].nil? or data[i][j][k].nil?

5 个答案:

答案 0 :(得分:3)

我通常会这样做:

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

答案 1 :(得分:2)

您可以略微缩短为

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)

答案 2 :(得分:2)

以下是三种不同的选择:

缩短

您可以使用“!”代替.nil?来缩短它:

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

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

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

摘要这些细节

上面的两个代码片段都很讨厌,我可能不会在代码库中多次编写它们。

三维数组看起来很复杂,你不应该直接在代码中的很多地方访问它。您应该考虑将其包装在具有适当名称的对象中:

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

答案 3 :(得分:2)

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

module ResponsiveNil
  refine NilClass do
    def [](obj)
      nil 
    end
  end
end

using ResponsiveNil
a = [[1]]
p a[2][3][4]  #=> nil

答案 4 :(得分:0)

以下内容允许任意数量的嵌套,并允许数组元素的值为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