【问题标题】:Memory-efficient Boolean arrays in RubyRuby 中的内存高效布尔数组
【发布时间】:2022-01-28 23:35:57
【问题描述】:

在 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 版本的东西,我更喜欢更简单的代码。 p>

【问题讨论】:

    标签: arrays ruby memory boolean


    【解决方案1】:

    您可能正在寻找二进制文件String 或名为IO::Buffer 的新Ruby 3.1 功能。要进一步压缩位(每字节 8 位),您需要执行以下操作:

    class BitString
      include Enumerable
    
      def initialize(size)
        @size = size
        @str = "\0".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
    

    【讨论】:

    • 完美!不知何故,当使用它时,ObjectSpace.memsize_of(sieve)(来自require 'objspace)返回40,而sieve.length10001。这显然是错误的,所以我实际上不知道它占用了多少
    猜你喜欢
    • 2011-10-05
    • 2023-03-22
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 2018-02-09
    相关资源
    最近更新 更多