Ruby 中的内存高效布尔数组
Memory-efficient Boolean arrays in Ruby
在 C 中,我可以声明一个填充有 0
的大型布尔数组,如下所示:
_Bool* sieve = malloc(limit + 1);
在Python中:
sieve = bytearray({False}) * (limit + 1)
在 Ruby 中,我可以这样做:
sieve = [false] * (limit + 1)
但这似乎占用了很多内存; Python 版本占用 len(sieve) + 57
字节,但 Ruby 版本占用 sieve.length * 8 + 40
字节。
有什么办法可以让布尔值的数组更短吗?我对像 Python 版本的东西很好,所以它 没有 像 C 一样是 sieve.length
字节,如果它的话我更喜欢更简单的代码实现类似 Python 版本的东西。
您可能正在寻找二进制 String
或名为 IO::Buffer
的新 Ruby 3.1 功能。要进一步压缩位(每字节 8 位),您需要执行以下操作:
class BitString
include Enumerable
def initialize(size)
@size = size
@str = "[=10=]".b * (size / 8.0).ceil
end
attr_reader :size
alias length size
def [](bit)
(@str[bit / 8].ord >> (7 - bit % 8) & 1) == 1
end
def []=(bit, val)
@str[bit / 8] = case val
when true
@str[bit / 8].ord | (1 << (7 - bit % 8))
when false
@str[bit / 8].ord & ~(1 << (7 - bit % 8))
else
raise ArgumentError, "can only set a boolean value on a BitString"
end.chr
end
def each(&block)
return enum_for(:each) { @size } unless block_given?
@size.times { |i| yield self[i] }
end
def to_s
@str
end
end
bs = BitString.new(10)
bs.length
# => 10
bs[3] = true
bs.to_s
# => "\x10\x00"
bs[3]
# => true
bs.map { |i| i ? 1 : 0 }
# => [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
bs.any?
# => true
bs[3] = false
bs.any?
# => false
在 C 中,我可以声明一个填充有 0
的大型布尔数组,如下所示:
_Bool* sieve = malloc(limit + 1);
在Python中:
sieve = bytearray({False}) * (limit + 1)
在 Ruby 中,我可以这样做:
sieve = [false] * (limit + 1)
但这似乎占用了很多内存; Python 版本占用 len(sieve) + 57
字节,但 Ruby 版本占用 sieve.length * 8 + 40
字节。
有什么办法可以让布尔值的数组更短吗?我对像 Python 版本的东西很好,所以它 没有 像 C 一样是 sieve.length
字节,如果它的话我更喜欢更简单的代码实现类似 Python 版本的东西。
您可能正在寻找二进制 String
或名为 IO::Buffer
的新 Ruby 3.1 功能。要进一步压缩位(每字节 8 位),您需要执行以下操作:
class BitString
include Enumerable
def initialize(size)
@size = size
@str = "[=10=]".b * (size / 8.0).ceil
end
attr_reader :size
alias length size
def [](bit)
(@str[bit / 8].ord >> (7 - bit % 8) & 1) == 1
end
def []=(bit, val)
@str[bit / 8] = case val
when true
@str[bit / 8].ord | (1 << (7 - bit % 8))
when false
@str[bit / 8].ord & ~(1 << (7 - bit % 8))
else
raise ArgumentError, "can only set a boolean value on a BitString"
end.chr
end
def each(&block)
return enum_for(:each) { @size } unless block_given?
@size.times { |i| yield self[i] }
end
def to_s
@str
end
end
bs = BitString.new(10)
bs.length
# => 10
bs[3] = true
bs.to_s
# => "\x10\x00"
bs[3]
# => true
bs.map { |i| i ? 1 : 0 }
# => [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
bs.any?
# => true
bs[3] = false
bs.any?
# => false