Reputation: 2339
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
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
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
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
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