我需要找出data[i][j][k]
元素是否存在,但我不知道data[i]
或data[i][j]
本身是否为零
如果我只是data[i][j][k].nil?
,如果data[I]或data[I][j]是nil
,它会抛出undefined method [] for nil:NilClass
所以,我现在使用
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]
的存在?
我通常这样做:
unless (data[i][j][k] rescue false)
# do something
end
这里有三种不同的替代方案:
缩短
您可以使用"!
"而不是.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
新功能"精化"是一个选项:
module ResponsiveNil
refine NilClass do
def [](obj)
nil
end
end
end
using ResponsiveNil
a = [[1]]
p a[2][3][4] #=> nil
您可以稍微缩短为
if data[i] && data[i][j] && data[i][j][k]
# do something with data[i][j][k]
end
你也可以你的"andand"宝石,它允许你写:
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)
以下允许任何数量的嵌套,并允许数组的元素值为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
您可以使用Array#dig
:
item = data.dig(i, j, k)
如果其中一个索引无效,它将返回nil
。