Diego-MX
Diego-MX

Reputation: 2339

Converting a boolean sequence to an integer

I have four boolean variables v0, v1, v2, v3 and want to get the integer expressed by them, taking the v's as binary digits, and their values false as 0 and true as 1, in other words:

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

What is the best way to cast them to such integers? Can this be done directly in a vector?

Upvotes: 0

Views: 783

Answers (4)

Wand Maker
Wand Maker

Reputation: 18762

You can monkey-patch TrueClass and FalseClass to respond to * and + methods. Here is a working solution largely based on discussion in this topic - 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

Upvotes: 1

sawa
sawa

Reputation: 168081

Just iterate. No need of power operation.

[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

Upvotes: 5

hedgesky
hedgesky

Reputation: 3311

In this certain example you could add to_i method directly to true and false:

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])

It works because true (same for false) is just simple object in ruby and thus you could extend it. Also you could write the same in slightly different way:

class TrueClass
  def to_i
    1
  end
end

class FalseClass
  def to_i
    0
  end
end

First approach works because there is always only one instance of TrueClass and FalseClass in the system.

Upvotes: 1

Simone Carletti
Simone Carletti

Reputation: 176372

Just create a custom method:

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)

You can of course use an array and apply the function call to all the values in the list.

ary = [false, true, true, false]

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

This is more concise. The first item in the array is the exponent, the second is the sum.

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

As pointed out in the comments, you can also use <<

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

Upvotes: 3

Related Questions