Ruby整数子串(子位?)

时间:2016-12-22 04:28:26

标签: ruby bit-manipulation

子字符串在"hello"[0..2]返回"hel"

的情况下工作

是否有整数等值,返回子位,如9[1..3]返回4"100"

上下文:

我试图做一个遗传算法,并且有一个跨越阶段,你将两条染色体分成两部分,然后交换一半,例如"10101010""00000000"的{​​{1}}交叉i = 4将为"00001010", "10100000"

但是,我这样做了几百万次,所以使用字符串效率很低,有没有一种方法可以做到这一点?

1 个答案:

答案 0 :(得分:1)

您可以考虑优化类Fixnum以允许Fixnum#[]的参数为位索引或位索引范围。

module StabBitRange
  def [](arg)
    case arg
    when Range
      mask = arg.reduce(0) { |n, idx| n |= (1 << idx) }
      (self & mask) >> arg.first
    else
      super
    end
  end
end

module StabBits
  refine Fixnum do
    prepend StabBitRange
  end
end

请参阅RefinementsModule#prependPrepend StabBitRange将其中包含的方法(此处只有一个)移动到祖先链中Fixnum中具有相同名称的方法之前。替代方法(在Ruby v2.0中引入Prepend之前常用)是别名Fixnum#[],然后将Fixnum[]重新定义为采用位索引或范围的新方法比特指数。 (请参阅此答案的编辑历史以了解如何完成此操作。)我希望读者同意Prepend是一种更明智的方法。

要使此代码可供使用,我们只需要调用关键字using

using StabBits

n = 682
n.to_s(2) #=> "1010101010" 

n[0]      #=> 0 
n[1]      #=> 1 
n[2]      #=> 0

n[0..7]   #=> 170 170.to_s(2) => "10101010" 
n[1..7]   #=> 85   85.to_s(2) => "1010101"
n[2..6]   #=> 10   10.to_s(2) => "1010"

当调用StabBitRange#\[\]并且参数不是范围时,super会调用Fixnum#[]并传递参数。该方法处理参数错误,并在没有错误时返回所需的位。

在IRB中运行此代码时,会引发以下异常:RuntimeError: main.using is permitted only at top level。那是因为IRB运行在顶层,但是从Ruby解析器的角度来看,在IRB中运行的代码运行在更高级别。要在IRB中运行它,必须将using StabBits和代码包含在模块中。