Bitmasking in Ruby: Get numbers which generated the bitmask - ruby

Currently I am storing a combination of a group of items as a single integer (bitmasked value) as in the example below:
Example:
1 - Orange
2 - Banana
4 - Cherry
8 - Apple
And then if the user selects Orange (1) and Apple (8) then the sum of those is 9.
And it is always and only when those two items are combined this value is 9.
And you are able to recover the original two numbers which were used to generate this number.
Here is an example website which does the trick:
http://www.tfxsoft.com/playground/calc.php
What I need:
I need an algoritm (preferrably in Ruby) which would take the sum (9) of those two bitmask values and return the values which it "contains" ( 1 and 4).

I think this might be what you're looking for:
FRUIT = { 1 => 'Orange', 2 => 'Banana', 4 => 'Cherry', 8 => 'Apple' }
def mask_fruit(a, b) a | b end
def unmask_fruit(masked)
FRUIT.select { |k, _| (masked | k) == masked }
end
mask = mask_fruit 1, 8 # => 9
unmask_fruit mask # => {1=>"Orange", 8=>"Apple"}

As I understand you want to find position of bits. Here is simple but not optimal solution:
2.1.5 :033 > 9.to_s(2).reverse.chars.map.with_index { |b, i| b == "1" ? i + 1 : nil }.compact
=> [1, 4]

Related

Find the smallest 4-digit number that decreases by 27 when you move its last digit to the first position. (Use the find or detect method) in Ruby

I'm trying to run standard ruby training programs, but I had a problem with this program, please take a look. Thank you very much!
Code:
q = 9999 #last 4-digit number
while q > 1000 #from 9999 to 1000, for exemple, the cycle has arrived to 6784
d = q.to_s.chars.map(&:to_i) #transform 6784 to array [6, 7, 8, 4]
p = d # create sample array with [6, 7, 8, 4]
tmp = p[0]; # tmp = 6;
p[0] = p[3]; # 6 = 4;
p[3] = tmp; # 4 = 6
g = p.join.to_i # transform [4, 7, 8, 6] to 4786
f = q - g # 6784 - 4786
if f == 27 # i need to find the smallest 4-digit number that decreases by 27 when moving its last digit to the first position
puts q #print 4-digit number that decreases by 27 when moving its last digit to the first position
end
q = q - 1;
end
But the result does not appear, it is because it is not, or somewhere a mistake.
In general, the condition of the task is:
Find the smallest 4-digit number that decreases by 27 when you move its last digit to the first position. (Use the find or detect method). Thank You!
I will first create a helper method to convert an array of digits to an integer.
def digits_to_int(arr)
arr.reduce { |n,d| n*10 + d }
end
For example,
digits_to_int [1,2,3,4]
#=> 1234
This tends to be faster than arr.join.to_i (see sawa's answer here).
We can then simply compute
(1..).find { |n| n-27 == digits_to_int(n.digits.rotate.reverse) }
#=> 30
See Enumerable#reduce (a.k.a. inject), "Endless range", Integer#digits, Array#rotate and Array#reverse.
Here is an example calculation.
n = 243
a = n.digits
#=> [3,4,2]
b = a.rotate
#=> [4,2,3]
c = b.reverse
#=> [3,2,4]
d = digits_to_int(c)
#=> 324
n - 27 == d
#=> 243 - 27 == 324 => false
and another
n = 30
a = n.digits
#=> [0,3]
b = a.rotate
#=> [3,0]
c = b.reverse
#=> [0,3]
d = digits_to_int(c)
#=> 3
n - 27 == d
#=> 30 - 27 == 3 => true
I would define a method to "rotate" the number using string manipulation.
def rotate_number_one_digit(n)
s = n.to_s
"#{s[-1]}#{s[0..-2]}".to_i
end
Then I would use #upto to deal with the iteration.
1000.upto(9999) do |x|
end
Each time around you'll check that the "rotated" number plus 27 equals x. If so, print it and break the loop to prevent further unnecessary iteration.
1000.upto(9999) do |x|
if rotate_number_one_digit(x) + 27 == x then
puts x
break
end
end
Or we can just use the #find method from Enumerable.
1000.upto(9999).find { |x| rotate_number_one_digit(x) + 27 == x }
Or using break to return a value from the loop.
1000.upto(9999) { |x|
break x if rotate_number_one_digit(x) + 27 == x
}

I keep getting an error that I don't understand

I am trying to create a function that takes a string in it's parameters. It's supposed to determine the highest and lowest numeric values in the string and return them unchanged.
Here's my code:
def high_and_low(numbers)
numbers.split
numbers.each {|x| x.to_i}
return numbers.max().to_s, numbers.min().to_s
end
Here's the error:
main.rb:5:in `high_and_low': undefined method `each' for "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6":String (NoMethodError)
from main.rb:8:in `<main>'
You have not changed the value from string to array.
Replace numbers.split with numbers = numbers.split.
Also you will need to change from numbers.each { |x| x.to_i } to numbers.map!(&:to_i). Otherwise you don't save integers anywhere.
BTW you don't have to use () and return (if it's in the end) so you can write [numbers.max.to_s, numbers.min.to_s].
Something like this should work:
def high_and_low(numbers)
numbers = numbers.split.map(&:to_i)
[numbers.max, numbers.min].map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
And bonus (one liner, not that you should write code this way):
def high_and_low(numbers)
numbers.split.map(&:to_i).sort.values_at(-1, 0).map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
The other answer is a good approach too so I include it here:
numbers.split.minmax_by { |n| -n.to_i }
Ruby has some nice methods available to make this much more simple:
"2 1 0 -1 -2".split.map(&:to_i).minmax
# => [-2, 2]
Breaking it down:
"2 1 0 -1 -2".split # => ["2", "1", "0", "-1", "-2"]
.map(&:to_i) # => [2, 1, 0, -1, -2]
.minmax # => [-2, 2]
If you want string versions of the values back, compare two integers in a block. minmax will return the values at the corresponding positions in the source array:
"2 1 0 -1 -2".split.minmax{ |a, b| a.to_i <=> b.to_i }
# => ["-2", "2"]
or:
"2 1 0 -1 -2".split.minmax_by{ |a| a.to_i }
# => ["-2", "2"]
minmax and minmax_by do the heavy lifting. The first is faster when there isn't a costly lookup to find the values being compared such as this case where the values are in an array and only needed to_i to compare them.
The *_by version performs a "Schwartzian transform" which basically remembers the values in the block as they're compared so the costly lookup only occurs once. (Many of Enumerable's methods have *_by versions.) These versions of the methods can improve the speed when you want to compare two values that are nested, perhaps in arrays of hashes of hashes, or objects within objects within objects.
Note: When comparing string versions of numbers it's important to convert to a numeric value when comparing. ASCII and strings order differently than numbers, hence the use of to_i.

given n, how to find the number of different ways to write n as the sum of 1, 3, 4 in ruby?

Problem: given n, find the number of different ways to write n as the sum of 1, 3, 4
Example:for n=5, the answer is 6
5=1+1+1+1+1
5=1+1+3
5=1+3+1
5=3+1+1
5=1+4
5=4+1
I have tried with permutation method,but its efficiency is very low,is there a more efficient way to do?
Using dynamic programming with a lookup table (implemented with a hash, as it makes the code simpler):
nums=[1,3,4]
n=5
table={0=>1}
1.upto(n) { |i|
table[i] = nums.map { |num| table[i-num].to_i }.reduce(:+)
}
table[n]
# => 6
Note: Just checking one of the other answers, mine was instantaneous for n=500.
def add_next sum, a1, a2
residue = a1.inject(sum, :-)
residue.zero? ? [a1] : a2.reject{|x| residue < x}.map{|x| a1 + [x]}
end
a = [[]]
until a == (b = a.flat_map{|a| add_next(5, a, [1, 3, 4])})
a = b
end
a:
[
[1, 1, 1, 1, 1],
[1, 1, 3],
[1, 3, 1],
[1, 4],
[3, 1, 1],
[4, 1]
]
a.length #=> 6
I believe this problem should be addressed in two steps.
Step 1
The first step is to determine the different numbers of 1s, 3s and 4s that sum to the given number. For n = 5, there are only 3, which we could write:
[[5,0,0], [2,1,0], [1,0,1]]
These 3 elements are respectively interpreted as "five 1s, zero 3s and zero 4s", "two 1s, one 3 and zero 4s" and "one 1, zero 3s and one 4".
To compute these combinations efficiently, I first I compute the possible combinations using only 1s, that sum to each number between zero and 5 (which of course is trivial). These values are saved in a hash, whose keys are the summands and the value is the numbers of 1's needed to sum to the value of the key:
h0 = { 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5 }
(If the first number had been 2, rather than 1, this would have been:
h0 = { 0 => 0, 2 => 1, 4 => 2 }
since there is no way to sum only 2s to equal 1 or 3.)
Next we consider using both 1 and 3 to sum to each value between 0 and 5. There are only two choices for the number of 3s used, zero or one. This gives rise to the hash:
h1 = { 0 => [[0,0]], 1 => [[1,0]], 2 => [[2,0]], 3 => [[3,0], [0,1]],
4 => [[4,0], [1,1]], 5 => [[5,0], [2,1]] }
This indicates, for example, that:
there is only 1 way to use 1 and 3 to sum to 1: 1 => [1,0], meaning one 1 and zero 3s.
there are two ways to sum to 4: 4 => [[4,0], [1,1]], meaning four 1s and zero 3s or one 1 and one 3.
Similarly, when 1, 3 and 4 can all be used, we obtain the hash:
h2 = { 5 => [[5,0,0], [2,1,0], [1,0,1]] }
Since this hash corresponds to the use of all three numbers, 1, 3 and 4, we are concerned only with the combinations that sum to 5.
In constructing h2, we can use zero 4s or one 4. If we use use zero 4s, we would use one 1s and 3s that sum to 5. We see from h1 that there are two combinations:
5 => [[5,0], [2,1]]
For h2 we write these as:
[[5,0,0], [2,1,0]]
If one 4 is used, 1s and 3s totalling 5 - 1*4 = 1 are used. From h1 we see there is just one combination:
1 => [[1,0]]
which for h2 we write as
[[1,0,1]]
so
the value for the key 5 in h2 is:
[[5,0,0], [2,1,0]] + [[1,0,1]] = [[5,0,0], [2,1,0]], [1,0,1]]
Aside: because of form of hashes I've chosen to represent hashes h1 and h2, it is actually more convenient to represent h0 as:
h0 = { 0 => [[0]], 1 => [[1]],..., 5 => [[5]] }
It should be evident how this sequential approach could be used for any collection of integers whose combinations are to be summed.
Step 2
The numbers of distinct arrangements of each array [n1, n3, n4] produced in Step 1 equals:
(n1+n3+n4)!/(n1!n3!n4!)
Note that if one of the n's were zero, these would be binomial coefficients. If fact, these are coefficients from the multinomial distribution, which is a generalization of the binomial distribution. The reasoning is simple. The numerator gives the number of permutations of all the numbers. The n1 1s can be permuted n1! ways for each distinct arrangement, so we divide by n1!. Same for n3 and n4
For the example of summing to 5, there are:
5!/5! = 1 distinct arrangement for [5,0,0]
(2+1)!/(2!1!) = 3 distinct arrangements for [2,1,0] and
(1+1)!/(1!1!) = 2 distinct arrangements for [1,0,1], for a total of:
1+3+2 = 6 distinct arrangements for the number 5.
Code
def count_combos(arr, n)
a = make_combos(arr,n)
a.reduce(0) { |tot,b| tot + multinomial(b) }
end
def make_combos(arr, n)
arr.size.times.each_with_object([]) do |i,a|
val = arr[i]
if i.zero?
a[0] = (0..n).each_with_object({}) { |t,h|
h[t] = [[t/val]] if (t%val).zero? }
else
first = (i==arr.size-1) ? n : 0
a[i] = (first..n).each_with_object({}) do |t,h|
combos = (0..t/val).each_with_object([]) do |p,b|
prev = a[i-1][t-p*val]
prev.map { |pr| b << (pr +[p]) } if prev
end
h[t] = combos unless combos.empty?
end
end
end.last[n]
end
def multinomial(arr)
(arr.reduce(:+)).factorial/(arr.reduce(1) { |tot,n|
tot * n.factorial })
end
and a helper:
class Fixnum
def factorial
return 1 if self < 2
(1..self).reduce(:*)
end
end
Examples
count_combos([1,3,4], 5) #=> 6
count_combos([1,3,4], 6) #=> 9
count_combos([1,3,4], 9) #=> 40
count_combos([1,3,4], 15) #=> 714
count_combos([1,3,4], 30) #=> 974169
count_combos([1,3,4], 50) #=> 14736260449
count_combos([2,3,4], 50) #=> 72581632
count_combos([2,3,4,6], 30) #=> 82521
count_combos([1,3,4], 500) #1632395546095013745514524935957247\
00017620846265794375806005112440749890967784788181321124006922685358001
(I broke the result the example (one long number) into two pieces, for display purposes.)
count_combos([1,3,4], 500) took about 2 seconds to compute; the others were essentially instantaneous.
#sawa's method and mine gave the same results for n between 6 and 9, so I'm confident they are both correct. sawa's solution times increase much more quickly with n than do mine, because he is computing and then counting all the permutations.
Edit: #Karole, who just posted an answer, and I get the same results for all my tests (including the last one!). Which answer do I prefer? Hmmm. Let me think about that.)
I don't know ruby so I am writing it in C++
say for your example n=5.
Use dynamic programming set
int D[n],n;
cin>>n;
D[0]=1;
D[1]=1;
D[2]=1;
D[3]=2;
for(i = 4; i <= n; i++)
D[i] = D[i-1] + D[i-3] + D[i-4];
cout<<D[i];

Find in a hash any values greater then a specific value

Suppose I have this hash
{ 1 => 4 , 2 => 3 , 4 => 1}
Now I want to make a loop where I can find any value which is greater then 3.
I know with hash.values?3 I can find the pairs has a value of 3.
But how can I find all the values which are greater of equal as 3.
Roelof
Edit 1 :
I try to make this pseudo code at work in ruby.
while there are sets of 3 ones:
remove the set from the hash (h[1] -= 3)
sum 1000 to the score
end
Use #select method:
{a: 1, b: 2, c: 3}.select{|k,v| v > 1}

Ruby Array - highest integer

brand new to Ruby, and love it. Just playing around with the below code:
public
def highest
highest_number = 0
each do |number|
number = number.to_i
highest_number = number if number > highest_number
puts highest_number
end
end
array = %w{1 2 4 5 3 8 22 929 1000 2}
array.highest
So at the moment the response I get is:
1
2
4
5
5
8
22
929
1000
1000
So it puts the array first, then the highest number from the array as well. However all I want it to is put the highest number only...
I have played around with this and can't figure it out! Sorry for such a newbie question
The problem is that you have the puts statement inside the each loop, so during every iteration it prints out what the highest number currently is. Try moving it outside the each loop so that you have this:
public
def highest
highest_number = 0
each do |number|
number = number.to_i
highest_number = number if number > highest_number
end
puts highest_number
end
array = %w{1 2 4 5 3 8 22 929 1000 2}
array.highest
Which produces the desired output:
1000
You could also save yourself some trouble by using max_by:
>> a = %w{1 2 4 5 3 8 22 929 1000 2}
=> ["1", "2", "4", "5", "3", "8", "22", "929", "1000", "2"]
>> m = a.max_by { |e| e.to_i }
=> "1000"
You could also use another version of max_by:
m = a.max_by(&:to_i)
to avoid the extra noise of the "block that just calls a method".
But this is probably a Ruby blocks learning exercise for you so using existing parts of the standard libraries doesn't count. OTOH, it is good to know what's in the standard libraries so punting to max_by or max would also count as a learning exercise.
You can do this instead and avoid the highest_number variable.
array = %w{1 2 4 5 3 8 22 929 1000 2}
class Array
def highest
collect { |x| x.to_i }. \
sort. \
last.to_i
end
end
array.highest # 1000
The collect { |x| x.to_i } can also be written as collect(&:to_i) in this case.

Resources