我可以在Ruby中创建使用默认值的数组? [英] Can I create an array in Ruby with default values?

查看:141
本文介绍了我可以在Ruby中创建使用默认值的数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Perl是pretty关于默认值漂亮的:

Perl is pretty nice about default values:

: jmglov@laurana; perl -e '@foo; printf "%d\n", $foo[123]'
0
: jmglov@laurana; perl -e '%foo; printf "%d\n", $foo{bar}'
0

红宝石可以做同样的,至少对散列:

Ruby can do the same, at least for hashes:

>> foo = Hash.new(0)
=> {}
>> foo[:bar]
=> 0

不过貌似同样不数组工作:

But the same seemingly does not work for arrays:

>> foo = Array.new(0)
=> []
>> foo[123]
=> nil
>> foo[124] = 0
=> 0
>> foo[456] = 0
=> 0
>> foo[455,456]
=> [nil, 0]

是否有可能提供了数组的默认值,所以当他们自动延长,他们充满了0,而不是零?

Is it possible to supply a default value for arrays, so when they are auto-extended, they're filled with 0 instead of nil?

当然,我可以解决此问题,但在成本前pressiveness:

Of course I can work around this, but at a cost to expressiveness:

>> 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.+

更新1:我的一个同事指出,我可以使用 #compact 来解决 #inject 的问题, #to_i 来解决标准的元素在指数的问题:

Update 1: One of my colleagues pointed out that I can use #compact to solve the #inject issue, and #to_i to solve the standard element-at-index issue:

>> 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]

更新2:感谢安德鲁格林为解决 + = 问题:

>> foo = []
=> []
>> def foo.[](i)
>>   fetch(i) {0}
>> end
=> nil
>> foo[4]
=> 0
>> foo
=> []
>> foo[4] += 123
=> 123
>> foo
=> [nil, nil, nil, nil, 123]

更新3:这是开始看起来像捶一个痣

Update 3: this is starting to look like whack-a-mole!

>> foo
=> [nil, nil, nil, nil, 123]
>> foo[-2..-1]
TypeError: can't convert Range into Integer

但是,我们可以处理的:

But we can deal with that:

>> 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]

我现在不得不承认(不好意思地)我会继承阵列来避免弄乱我的code:

I now have to admit (sheepishly) that I'll subclass Array to avoid cluttering my code:

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

感谢所有的创造性的解决方案。 TIMTOWTDI哉!

Thanks for all the creative solutions. TIMTOWTDI indeed!

推荐答案

由于红宝石返回为不存在的元素(相对指数外-bounds类型的错误),你可以只使用一个或

Given that Ruby returns nil for a non-existing element (as opposed to index-out-of-bounds type error), you could just use an "or":

a = [1,2,3]
puts a[5]  # => nil
puts a[5] || "a default"  # => a default

您可以采取猴子打补丁的方法,但你可能不希望这样做的任何事情比1文件脚本较大的:

You could take the monkey patch approach, but you probably would not want to do this in anything larger than a 1-file script:

a = [1,2,3]
def a.[](index)
  self.at(index) ? self.at(index) : "a default"
end
puts a[5]   # => "a default"

这篇关于我可以在Ruby中创建使用默认值的数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆