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