【问题标题】:Converting a boolean sequence to an integer将布尔序列转换为整数
【发布时间】:2016-04-14 06:34:05
【问题描述】:

我有四个布尔变量v0, v1, v2, v3,想要得到它们表示的整数,将v作为二进制数字,将它们的值false作为0true作为1 ,换句话说:

8 * v3 + 4 * v2 + 2 * v1 + v0

将它们转换为此类整数的最佳方法是什么?这可以直接在向量中完成吗?

【问题讨论】:

  • @CarySwoveland 你是说D[v3] 因为D(v3) 不适合我吗?
  • 你可以写成 8*D[v3] + 4*D[v2] + 2*D[v1] + D[v0],其中 D = { true=>1, false=>0 }
  • @Wand,谢谢。你总是那么外交。旁白:在你的下一个化身中,你挥动一根魔杖怎么样?
  • @CarySwoveland 完成!

标签: ruby


【解决方案1】:

只是迭代。无需电源操作。

[false, true,  false, true] .inject(0){|n, b| n * 2 + (b ? 1 : 0)} # => 5
[false, false, false, false].inject(0){|n, b| n * 2 + (b ? 1 : 0)} # => 0
[false, false, false, true] .inject(0){|n, b| n * 2 + (b ? 1 : 0)} # => 1
[true,  false, false, true] .inject(0){|n, b| n * 2 + (b ? 1 : 0)} # => 9

【讨论】:

  • 我倾向于使用<<,因为这是我们在汇编程序中的想法。
  • 这是学习一门新语言的好处之一。仅仅看它很难理解,即使知道它做了什么并且很短(当然是新手)。但随后在inspect 上快速谷歌并重新访问块,然后它使 Ruby 变得更加丰富。
【解决方案2】:

只需创建一个自定义方法:

def bool_to_int(bool)
  bool ? 1 : 0
end

8*bool_to_int(v3) + 4*bool_to_int(v2) + 2*bool_to_int(v1) + bool_to_int(v0)

您当然可以使用数组并将函数调用应用于列表中的所有值。

ary = [false, true, true, false]

exp = 0
ary.inject(0) do |total, value|
  total += bool_to_int(value) * (2**exp)
  exp += 1
  total
end

这样更简洁。数组中的第一项是指数,第二项是总和。

ary = [false, true, true, false]
ary.inject([0,0]) do |(exp, total), value|
  [exp + 1, total + bool_to_int(value) * (2**exp)]
end

正如 cmets 中指出的,您也可以使用 <<

ary = [false, true, true, false]
ary.inject([0,0]) do |(exp, total), value|
  [exp + 1, total + (bool_to_int(value) << exp)]
end

【讨论】:

  • n * (2**exp) 等价于n &lt;&lt; exp
  • 你也可以使用each_with_index来避免数组:ary.each_with_index.inject(0) { |total, (value, exp)| total + (bool_to_int(value) &lt;&lt; exp) }
【解决方案3】:

在这个特定示例中,您可以将to_i 方法直接添加到truefalse

def false.to_i
  0
end

def true.to_i
  1
end

def int_from_boolean_array(array)
  sum = 0  
  array.each_with_index do |el, index|
    sum += el.to_i * (2**index)
  end
  sum
end

int_from_boolean_array([false, true, false, true])

它之所以有效是因为truefalse 也是如此)只是 ruby​​ 中的简单对象,因此您可以对其进行扩展。你也可以用稍微不同的方式写同样的东西:

class TrueClass
  def to_i
    1
  end
end

class FalseClass
  def to_i
    0
  end
end

第一种方法有效,因为系统中始终只有一个 TrueClassFalseClass 实例。

【讨论】:

  • 对诸如 TrueClass 之类的低级类进行猴子补丁并不是一个好主意,更不用说您正在引入一种常见的强制转换方法,这肯定会在许多库中引起很多副作用。想想它对鸭子打字(respond_to?)使用的影响。这是一个非常糟糕的主意。
  • 你可以把它放在一个 Refinement 中,只在你自己的代码范围内激活 Refinement。
  • @SimoneCarletti 我明白了,这就是为什么我在答案的一开始就写了“在这个特定的例子中”。
  • 除了这个问题之外,也许还有to_i 方法被添加到Ruby 的TrueClassFalseClass 的情况。
  • 问题是 False/false 不是 0,它更相当于 nil。 0 更接近于真而不是假。对于特定的位旋转代码,它是可以的,但我看不到它是语言本身的一部分,因为它会在第一次遇到它的人的头脑中造成严重破坏。
【解决方案4】:

您可以对TrueClassFalseClass 进行猴子补丁以响应*+ 方法。这是一个主要基于本主题讨论的有效解决方案 - In Ruby, how does coerce() actually work?

# Changes to `TrueClass` and `FalseClass`
class TrueClass
    def *(i)
        i * 1
    end
    def +(i)
        i + 1
    end
    def coerce(something)
        [self, something]
    end
end

class FalseClass
    def *(i)
        i * 0
    end
    def +(i)
        i + 0
    end
    def coerce(something)
        [self,something]
    end
end

# Sample Runs

v3,v2,v1,v0 = true,false,true,true
p v3*8 + v2*4 + v1*2 + v0
#=> 11
p 8*v3 + 4*v2 + 2*v1 + v0
#=> 11
p 8*true + 4*false + 2*false + true
#=> 9

【讨论】:

  • 这个很有见地。虽然我知道我不应该打猴子补丁,但它有助于理解语言。
  • Rails Active Record Core Extensions 是非常有用的猴子补丁集。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-26
  • 2013-02-09
  • 1970-01-01
  • 2013-12-03
  • 2014-09-03
  • 1970-01-01
  • 2011-12-10
相关资源
最近更新 更多