我想通过创建3d数组来保存year-month-day
在ruby中以查找O(1):
dates = [Date.new(2014,2,15), Date.new(2015, 8, 27), Date.new(2014, 7, 4), ...]
res = []
dates.each do |d|
# Init year if DNE
if res[d.year].nil?
res[d.year] = []
end
# Init month if DNE
if res[d.year][d.month].nil?
res[d.year][d.month] = []
end
# Set the [year][month][day] = 1
res[d.year][d.month][d.day] = 1
end
# Use case
def date_in_array?(date)
!res[self.year].nil? && !res[self.year][self.month].nil? && !res[self.year][self.month][self.day].nil?
end
date_in_array?(Date.new(2014, 2, 15))
=> true
date_in_array?(Date.new(2014, 9, 21))
=> false
另一种方法是使用哈希来保存日期,但就内存而言可能会变得昂贵。
所以我的问题是,ruby如何管理数组索引超出范围?
我想确保通过执行res[2015] = []
,ruby不会初始化res[0..2014]
集,这确实是在这种情况下存储数据的好方法。
答案 0 :(得分:3)
我想确保通过执行
res[2015] = []
,ruby不会初始化res[0..2014]
集,这确实是在这种情况下存储数据的好方法。
不。确实如此。此片段只是通过占用大部分内存而使我的系统无法响应。坚实的证明。
@a = []
@a[1_000_000_000] = 1
如何存储数据取决于您期望作为键的值。
根据定义,数组是一大块连续的存储单元,每个存储单元存储一个值。实现了恒定的访问时间,因为对于任何已知的索引,它需要一个算术运算(基数+索引)来计算所需单元的存储器地址。如果键是非顺序的,那么你不应该首先使用数组。
磁盘不用于阵列存储,只能用于虚拟RAM(可配置为使用交换空间,但不要依赖它)。
如果按键是顺序的,但是不要接近0(即1990及以上),你可以为内置数组创建一个包装器,其中包含一个数组和一个"下限"用于计算真实指数"在那个数组中。实施[]
和[]=
,您将获得类似阵列的访问权限。
class ShiftedArray
def initialize(lower_bound)
@lower_bound = lower_bound
@storage = []
end
def []=(key, value)
@storage[key - @lower_bound] = value
end
def [](key)
@storage[key - @lower_bound]
end
end
ShiftedArray.new(1)
实际上是1索引数组。
当然,这远非理想,它不允许写入低于施工时设定界限的值。您可以实现这一点,但这超出了本答案的范围。
如果密钥是高度分散的数字,最好使用Hash
或搜索树作为数据结构。
答案 1 :(得分:2)
在Ruby中使用高索引初始化空数组是否很昂贵?
是。 Ruby将为您的示例中的条目0..2015分配内存。在这种情况下你确实想要哈希;散列查找(如tadman所述)是分摊的O(1),因此速度不应该是一个问题,并且内存使用量也应该比稀疏数组大大提高。
举例(MRI 2.2.2):
require 'objspace'
res = []; ObjectSpace.memsize_of res #=> 0
res = []; res[100] = true; ObjectSpace.memsize_of res # => 928
res = []; res[2015] = true; ObjectSpace.memsize_of res # => 16248
res = {}; res[100] = true; ObjectSpace.memsize_of res # => 192
res = {}; res[2015] = true; ObjectSpace.memsize_of res # => 192
答案 2 :(得分:1)
Hash可能比三重嵌套数组结构便宜得多。任何单个数组的开销都高于单个Hash条目的开销。
不要忘记Hash查找在技术上是 O(1),是恒定时间,所以这里不关心性能。还有其他选择。
这个超级松弛的版本是使用Set,它就像是Array和Hash之间的混合:
require 'set'
dates = Set.new([ Date.new(2014,2,15), Date.new(2015, 8, 27), Date.new(2014, 7, 4) ])
dates.include?(Date.new(2014,2,15))
# => true
dates.include?(Date.new(2014,2,5))
# => false
您可以将其调整为哈希,其中键是日期或字符串。您经常会发现最简单的解决方案足够快。