使用数字作为默认索引

时间:2017-01-24 01:11:01

标签: arrays ruby indexing

我有一个合理大小的数组,

a = ("a".."z").to_a

我希望使用某个默认号码,当用于将值作为索引调用时,它(实际上)始终返回nil

a[some_default_index] # => nil

对于固定a,我可以设置一个等于或大于a大小的固定数字作为默认数字,但a会有所不同。

我尝试了Float::NANFloat::Infinity,但没有按照我的意图行事。

a[Float::NAN] # => out of range error
a[Float::Infinity] # => out of range error

我可以使用哪个数字作为索引?

2 个答案:

答案 0 :(得分:2)

试试这个

max_index = 2**30 - 1
a[max_index] # => nil 

错误消息提供了提示RangeError: bignum too big to convert into `long'

也就是说,索引必须符合Ruby底层机器级表示中的long值。在32位系统上,在64位系统上为2**31 - 12**63 - 1

然而,这些值在Ruby中表示为Fixnum,所以如果你想利用立即加速的fixnums,最好使用它们的最大值。 Ruby使用标记指针来表示Fixnum整数,因此它们比原始整数小一点,因此对于32位系统而言2**30 - 1和对于64位系统而言2**62 - 1

答案 1 :(得分:1)

最大的正确索引

这是@AndrewGrimm的优秀版本answer

a = ("a".."z").to_a

start = Time.now
largest_correct_index = 1
smallest_incorrect_index = nil

until smallest_incorrect_index == largest_correct_index + 1
  if smallest_incorrect_index.nil?
    next_number_to_try = largest_correct_index * 1000
  else
    next_number_to_try = (smallest_incorrect_index + largest_correct_index) / 2 # Geometric mean would be more efficient, but more risky
  end

  if next_number_to_try <= largest_correct_index ||
       smallest_incorrect_index && next_number_to_try >= smallest_incorrect_index
    raise "Can't happen case"
  end

  begin
    a[next_number_to_try]
    largest_correct_index = next_number_to_try
  rescue RangeError
    smallest_incorrect_index = next_number_to_try
  end
end

finish = Time.now
puts "The largest correct index is #{largest_correct_index}"
puts "The smallest incorrect index is #{smallest_incorrect_index}"
puts "Calculation took #{finish - start} seconds"

在32位Ruby上,它返回2**31-1

The largest correct index is 2147483647
The smallest incorrect index is 2147483648
Calculation took 0.0 seconds

在64位Ruby和JRuby上,它返回2**63-1

The largest correct index is 9223372036854775807
The smallest incorrect index is 9223372036854775808
Calculation took 0.000250378 seconds

所以看起来@ akuhn的answer在大多数情况下都应该足够好。

替代

根据您的需要,您还可以使用哈希:

a = ('a'..'z').to_a
# ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

h = ('a'..'z').map.with_index { |l, i| [i, l] }.to_h
# {0=>"a", 1=>"b", 2=>"c", 3=>"d", 4=>"e", 5=>"f", 6=>"g", 7=>"h", 8=>"i", 9=>"j", 10=>"k", 11=>"l", 12=>"m", 13=>"n", 14=>"o", 15=>"p", 16=>"q", 17=>"r", 18=>"s", 19=>"t", 20=>"u", 21=>"v", 22=>"w", 23=>"x", 24=>"y", 25=>"z"}

require 'fruity'

compare do
  _array { a[rand(26)] }
  _hash  { h[rand(26)] }
end

它似乎不会对表现产生负面影响:

Running each test 16384 times. Test will take about 1 second.
_array is similar to _hash

所有这些:

h[-1]
h[:default]
h[Float::INFINITY]
h[2**1024-1]

会返回nil