Perl对默认值非常好:
: jmglov@laurana; perl -e '@foo; printf "%d\n", $foo[123]'
0
: jmglov@laurana; perl -e '%foo; printf "%d\n", $foo{bar}'
0
Run Code Online (Sandbox Code Playgroud)
Ruby可以做同样的事情,至少对于哈希来说:
>> foo = Hash.new(0)
=> {}
>> foo[:bar]
=> 0
Run Code Online (Sandbox Code Playgroud)
但是这些似乎对数组不起作用:
>> foo = Array.new(0)
=> []
>> foo[123]
=> nil
>> foo[124] = 0
=> 0
>> foo[456] = 0
=> 0
>> foo[455,456]
=> [nil, 0]
Run Code Online (Sandbox Code Playgroud)
是否可以为数组提供默认值,因此当它们自动扩展时,它们会被填充为0而不是nil?
当然,我可以解决这个问题,但要付出代价:
>> foo[457,458] = 890, 321
=> [890, 321]
>> foo[456] += 789
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+
>> foo.inject(0) {|sum, i| sum += (i || 0) }
=> 1211
>> foo.inject(:+)
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+
Run Code Online (Sandbox Code Playgroud)
更新1:我的一位同事指出,我可以#compact用来解决#inject问题,并#to_i解决标准元素索引问题:
>> foo.include? nil
=> true
>> foo.compact.inject(:+)
=> 1211
>> foo[456,457]
=> [0, 890, 321]
>> foo[455..457]
=> [nil, 0, 890]
>> foo[455..457].map(&:to_i)
=> [0, 0, 890]
Run Code Online (Sandbox Code Playgroud)
更新2:感谢Andrew Grimm解决此+=问题:
>> foo = []
=> []
>> def foo.[](i)
>> fetch(i) {0}
>> end
=> nil
>> foo[4]
=> 0
>> foo
=> []
>> foo[4] += 123
=> 123
>> foo
=> [nil, nil, nil, nil, 123]
Run Code Online (Sandbox Code Playgroud)
更新3:这开始看起来像打鼹鼠!
>> foo
=> [nil, nil, nil, nil, 123]
>> foo[-2..-1]
TypeError: can't convert Range into Integer
Run Code Online (Sandbox Code Playgroud)
但我们可以解决这个问题:
>> def foo.[](index)
>> if index.is_a? Range
>> index.map {|i| self[i] }
>> else
?> fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array
>> end
>> end
=> nil
>> foo
=> [nil, nil, nil, nil, 123]
>> foo[-2..-1]
=> [nil, 123]
Run Code Online (Sandbox Code Playgroud)
我现在必须(羞怯地)承认我将Array继承子类以避免混乱我的代码:
class MyClass
class ArrayWithDefault < Array
def [](index)
if index.is_a? Range
index.map {|i| self[i] }
else
fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
感谢所有创意解决方案.TIMTOWTDI确实!
lud*_*dde 130
不是自动扩展,而是使用默认值初始化为指定长度:
>> Array.new(123, 0)
=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)
Rob*_*own 17
假设Ruby返回nil一个不存在的元素(而不是索引越界类型错误),你可以使用"或":
a = [1,2,3]
puts a[5] # => nil
puts a[5] || "a default" # => a default
Run Code Online (Sandbox Code Playgroud)
您可以采用猴子补丁方法,但您可能不希望在比1文件脚本更大的范围内执行此操作:
a = [1,2,3]
def a.[](index)
self.at(index) || "a default"
end
puts a[5] # => "a default"
Run Code Online (Sandbox Code Playgroud)
小智 8
最简单的方法是:
new_array = Array.new(size, default_value)
Run Code Online (Sandbox Code Playgroud)
例如:
new_array = Array.new(5,"foo")
Run Code Online (Sandbox Code Playgroud)