Is there a method in ruby that allows breaking integers up into 1s, 10s, 100s, 1000s, ...?
I know that you can convert an integer to a string and parse the string to get the values mentioned above, but I would imagine there is a really simple way to do this with ruby like most other things. So far I have this:
1234.to_s.chars.reverse.each_with_index
.map{|character, index| character.to_i * 10**index }
# => [4, 30, 200, 1000]
But is there something specific to do this in ruby?
You could do that as follows:
n = 1020304
Math.log10(n).ceil.times.with_object([]) do |i,a|
n, d = n.divmod(10)
a << d * 10**i
end
#=> [4, 0, 300, 0, 20000, 0, 1000000]
Hmmm. That looks a bit odd. Maybe it would be better to return a hash:
Math.log10(n).ceil.times.with_object({}) do |i,h|
n, d = n.divmod(10)
h[10**i] = d
end
#=> {1=>4, 10=>0, 100=>3, 1000=>0, 10000=>2, 100000=>0, 1000000=>1}
def value_of_powers(number, base: 10)
number.to_s.reverse.each_char.with_index.map do |character, index|
base**index * character.to_i
end.reverse
end
value_of_powers(10212, base: 3) # => [81, 0, 18, 3, 2]
value_of_powers(1234) # => [1000, 200, 30, 4]
I reversed the order so that the values are read in the same order as we read numbers.
As shown, it also works for other base numbers. Given no base, it will default to base 10.
This isn't particularly clever, but I suppose it's relatively clear about what it does.
def tens_places(n, place = 1)
if n >= 1
[(n % 10).floor * place] + tens_places(n/10, place * 10)
else
[]
end
end
Related
Lets say I have an integer 98.
The binary representation of this string would be:
(98).to_s(2) # 1100010
Now I want to convert this binary string to an integer array of all the bits that are set. This would give me:
[64,32,2]
How would I go about this?
Update: The conversion of int to int array does not necessarily need to involve String, it is just what I knew. I assume non String operations would also be faster.
Ruby is amazing seeing all these different ways to handle this!
This would work:
i = 98
(0...i.bit_length).map { |n| i[n] << n }.reject(&:zero?)
#=> [2, 32, 64]
Fixnum#bit_length returns the position of the highest "1" bit
Fixnum#[n] returns the integer's nth bit, i.e. 0 or 1
Fixnum#<< shifts the bit to the left. 1 << n is equivalent to 2n
Step by step:
(0...i.bit_length).map { |n| i[n] }
#=> [0, 1, 0, 0, 0, 1, 1]
(0...i.bit_length).map { |n| i[n] << n }
#=> [0, 2, 0, 0, 0, 32, 64]
(0...i.bit_length).map { |n| i[n] << n }.reject(&:zero?)
#=> [2, 32, 64]
You might want to reverse the result.
In newer versions of Ruby (2.7+) you could also utilize filter_map and nonzero? to remove all 0 values:
(0...i.bit_length).filter_map { |n| (i[n] << n).nonzero? }
#=> [2, 32, 64]
Reverse the string, map it to binary code values of each digit, reject zeros. Optionally reverse it again.
s.reverse.chars.map.with_index{ |c, i| c.to_i * 2**i }.reject{ |b| b == 0 }.reverse
Or you could push the values to array with each_with_index
a = []
s.reverse.each_with_index do |c, i|
a.unshift c.to_i * 2**i
end
what is probably faster and more readable, but less idiomatic.
(98).to_s(2).reverse.chars.each_with_index.
map {|x,i| x=="1" ? 2**i : nil }.compact.reverse
Phew! Let's break that down:
First get the binary String as your example (98).to_s(2)
We will need to start 0-index from right hand side, hence .reverse
.chars.each_with_index gives us pairs such as [ '1', 4 ] for character at bit position
The .map converts "1" characters to their value 2 ** i (i.e. 2 to the power of current bit position) and "0" to nil so it can be removed
.compact to discard the nil values that you don't want
.reverse to have descending powers of 2 as your example
Here are a couple of ways:
#1
s = (98).to_s(2)
sz = s.size-1
s.each_char.with_index.with_object([]) { |(c,i),a| a << 2**(sz-i) if c == '1' }
# => [64, 32, 2]
#2
n = 2**(98.to_s(2).size-1)
arr = []
while n > 0
arr << n if 90[n]==1
n /= 2
end
arr
#=> [64, 32, 2]
I am solving the pyramid problem, in which an array is reduced to a single element over time by subtracting two consecutive numbers in each iteration.
input: [1, 5, 9, 2, 3, 5, 6]
iterations
[4, 4, -7, 1, 2, 1],
[0, -11, 8, 1, -1],
[-11, 19, -7, -2],
[30, -26, 5],
[-56, 31],
[87]
output: 87
What is the best way or ruby way to solve this problem? This can be done by inheriting array and making a new class, but I don't know how. Please help. I write this code to solve it:
a = [1,5,9,2,3,5,6]
class Array
def pyr
a = self.each_cons(2).to_a.map! { |e| e[1] - e[0] }
a
end
end
while a.length > 1
a = a.pyr
ans = a[0]
end
p ans
I see three ways to approach this.
Reopen the Array class
Sure, if in your particular ruby script/project this is an elementary functionality of an array, reopen the class. But if you are going to re-open a class, at least make sure the name is something meaningful. pyr? Why not write a full name, so no conflicts are possible, something like next_pyramid_iteration (I have never heard of this pyramid problem, so excuse me if I am way of base here).
Make a class inherit from Array
class Pyramid < Array
def next_iteration
self.each_const(2).map! { |e| e[1] - e[o] }
end
end
and then your calculation would become something like
pyramid = Pyramid.new([1,5,9,2,3,5,6])
while pyramid.length > 1
pyramid.next_iteration
end
pyramid[0]
Make a specific class to do the calculation
I am not quite sure what you are trying to achieve, but why not just make a specific class that knows how to calculate pyramids?
class PyramidCalculator
def initialize(arr)
#pyramid = arr
end
def calculate
while #pyramid.length > 1
do_next_iteration
end
#pyramid.first
end
def self.calculate(arr)
PyramidCalculator.new(arr).calculate
end
protected
def do_next_iteration
#pyramid = #pyramid.each_const(2).map! { |e| e[1] - e[o] }
end
end
because I added a convenience class-method, you can now calculate a result as follows:
PyramidCalculator.calculate([1,5,9,2,3,5,6])
My personal preference would be the last option :)
I would just do it as a two-liner.
a = a.each_cons(2).map{|e1, e2| e2 - e1} while a[1]
a.first # => 87
It's certainly easy enough to turn this into a simple function without hacking on the Array class:
def pyr(ary)
return ary[0] if ary.length < 2
pyr(ary.each_cons(2).map { |e| e[1] - e[0] })
end
p pyr [1,5,9,2,3,5,6] # => 87
Use return ary if you want the answer as a one-element array rather than a scalar.
If you prefer iteration to recursion or have a very large array:
def pyr(ary)
ary = ary.each_cons(2).map { |e| e[1] - e[0] } while ary.length > 1
ary
end
By encapsulating this as a function rather than doing it inline, you get the ability to do the operation on any number of arrays plus it's non-destructive on the original input array.
It's not necessary to compute the end value by successive computation of differences, which requires (n*(n-1)/2 subtractions and the same number of additions, where n is the size of the array a. Instead, we can compute that value by summing n terms of the form:
(-1)K+ibin_coeff(n-1,i)*a[i]
for i = 0..(n-1), where:
K equals 0 if the array has an even number of elements, else K equals 1; and
bin_coeff(n,i) is the binomial coefficient for choosing "n items i at a time" (n!/i!*(n-i)!).
I know what you're thinking: the calculation of each binomial coefficient will take some work. True, but that can be done in an efficient way (which I've not done below), by computing bin_coeff(n-1,i+1) from bin_coeff(n-1,i), etc. Of course, that's academic, as no one is likely to actually use the method I'm suggesting.
(I'm hoping nobody will demand a proof, but I'll try to oblige if a request is made.)
Code
class Fixnum
def factorial
(1..self).reduce(1) { |t,i| t*i }
end
def bin_coeff m
self.factorial/(m.factorial*(self-m).factorial)
end
end
def pyramid_sum(a)
n = a.size-1
sign = n.even? ? -1 : 1
(0..n).reduce(0) do |t,i|
sign = -sign
t + sign * n.bin_coeff(i) * a[i]
end
end
Examples
pyramid_sum [1, 5] #=> 4
pyramid_sum [1, 5, 9] # #=> 0
pyramid_sum [1, 5, 9, 2] #=> -11
pyramid_sum [1, 5, 9, 2, 3] #=> 30
pyramid_sum [1, 5, 9, 2, 3, 5] #=> -56
pyramid_sum [1, 5, 9, 2, 3, 5, 6] #=> 87
I have no clue how to call this in correct math-terms. Consider a method which takes two digits:
def num_of_sum(total, group_count)
end
where total is an integer and group_count is an integer.
How would I get a 'nicely' grouped Array of integers of group_count-length which sum up till total.
My spec would look like:
describe "number to sum of" do
it "grabs all numbers" do
expect(num_of_sum(10, 2)).to eq([5,5])
expect(num_of_sum(10, 3)).to eq([3,3,4])
expect(num_of_sum(20, 3)).to eq([6,7,7])
expect(num_of_sum(100, 3)).to eq([33,33,34])
expect(num_of_sum(100, 2)).to eq([50,50])
end
end
I tried this, which works:
def num_of_sum(total, in_groups_of)
result = []
section_count ||= (total.to_f / in_groups_of.to_f).round
while(total > 0)
total -= section_count
if (total - section_count) < 0 && (total + section_count).even?
section_count += total
total -= total
end
result << section_count
end
result
end
But, for instance, this spec doesn't work:
expect(num_of_sum(67,5)).to eq([13,13,13,14,14])
I need the array to contain numbers that are as close to each other as possible. But the array is limited to the length of the group_count.
Does someone know what the mathemetical name for this is, so I can search a bit more accurately?
The mathematical term for this is an integer partition
A more direct approach to this is to observe that if you do integer division (round down) of the total by the number of groups, then your sum would be short by total mod number_of_groups, so you just need to distribute that amount across the array:
def even_partition(total, number_of_groups)
quotient, remainder = total.divmod(number_of_groups)
(number_of_groups-remainder).times.collect {quotient} +
remainder.times.collect { quotient + 1}
end
def n_parts(num, groupcount)
div, mod = num.divmod(groupcount)
Array.new(groupcount-mod, div) + Array.new(mod, div+1)
end
n_parts(100,3) => [33, 33, 34]
Docs to Array.new and Fixnum.divmod
A naive implementation is like this:
Let's take example of (20, 3). You want three numbers as a result.
20 / 3 # => 6
This is your "base" value. Create an array of three sixes, [6, 6, 6]. That'll get you 18. Now you have to distribute remaining 2 as equally as possible. For example, enumerate array elements and increment each one by 1, until you have no value to distribute. Result is [7, 7, 6]. Good enough, I think.
Possible (working) implementation:
def breakdown(total, group_count)
avg_value, extra = total.divmod(group_count)
result = Array.new(group_count, avg_value)
extra.times do |i|
result[i] += 1
end
result
end
breakdown(10, 2) == [5, 5] # => true
breakdown(10, 3) == [4, 3, 3] # => true
breakdown(20, 3) # => [7, 7, 6]
I have no clue how it’s called, but here is a solution:
def num_of_sum sum, count
result = [i = sum / count] * count # prepare an array e.g. [3,3,3] for 10,3
result[sum - i * count..-1] + # these should be left intact
result[0...sum - i * count].map { |i| i + 1 } # these are ++’ed
end
Hope it helps.
Another way:
def floors_then_ceils(n, groups)
floor, ceils = n.divmod(groups)
groups.times.map { |i| (i < groups-ceils) ? floor : floor + 1 }
end
floors_then_ceils(10, 3)
#=> [3, 3, 4]
floors_then_ceils(9, 3)
#=> [3, 3, 3]
Alternatively, groups.times.map... could be replaced with:
Array.new(groups-ceils, floor).concat(Array.new(ceils, floor+1))
I'm doing an exercise now where I'm looking for all of the zeros in an array.
The input is:
numbers = [1, 3, 500, 200, 4000, 3000, 10000, 90, 20, 500000]
I want to sort them into a hash by the number of zeros. The expected output is:
expected = {0=>[1, 3], 2=>[500, 200], 3=>[4000, 3000], 4=>[10000], 1=>[90, 20], 5=>[500000]}
I have the structure built but I'm not sure how to count the number of zeros:
grouped = Hash.new {|hash, key| hash[key] = []}
numbers.each do |num|
grouped[num] << num
end
EDITED for clarity:
Any advice would be appreciated. Also, a lot of the advice I read on this recommended converting the array of integers to a string in order to solve the problem. Is there a way to count the number of digits (not just zeros) without converting the array to a string? The expected output in this case would look like:
expected = {1=>[1, 3], 2=>[90, 20], 3=>[500, 200], 4=>[4000, 3000], 5=>[10000], 6=>[500000]
Thanks in advance.
Like many transformations you'll want to do, this one's found in Enumerable.
Grouping by number of digits:
grouped = numbers.group_by { |n| Math.log10(n).to_i + 1 }
# => {1=>[1, 3], 3=>[500, 200], 4=>[4000, 3000], 5=>[10000], 2=>[90, 20], 6=>[500000]}
Grouping by number of zeroes:
grouped = numbers.group_by { |n| n.to_s.match(/0+$/) ? $&.length : 0 }
# => {0=>[1, 3], 2=>[500, 200], 3=>[4000, 3000], 4=>[10000], 1=>[90, 20], 5=>[500000]}
The group_by method is a handy way to convert an Array to a Hash with things organized into pigeon-holes.
I wound up using
grouped = Hash.new {|hash, key| hash[key] = []}
numbers.each do |num|
grouped[num.to_s.count('0')] << num
end
but I really liked the variation in responses. I didn't realize there were so many ways to go about this. Thank you everyone.
If you wish to group non-negative integers by the number of zero digits they contain, you can do this:
def nbr_zeroes(n)
return 1 if n == 0
m = n
i = 0
while m > 0
i += 1 if m % 10 == 0
m /= 10
end
i
end
numbers = [1, 3, 500, 200, 4000, 3000, 10000, 90, 20, 500000]
numbers.group_by { |i| nbr_zeroes(i) }
#=> { 0=>[1, 3], 2=>[500, 200], 3=>[4000, 3000], 4=>[10000] }
numbers = [100000, 100001, 304070, 3500040, 314073, 2000, 314873, 0]
numbers.group_by { |i| nbr_zeroes(i) }
#=> { 5=>[100000], 4=>[100001, 3500040], 3=>[304070, 2000],
# 1=>[314073, 0], 0=>[314873] }
Group by floor of log base 10?
1.9.3-p484 :014 > numbers.each {|n| grouped[Math.log10(n).floor] << n}
=> [1, 3, 500, 200, 4000, 3000, 10000, 90, 20, 500000]
1.9.3-p484 :016 > grouped
=> {0=>[1, 3], 2=>[500, 200], 3=>[4000, 3000], 4=>[10000], 1=>[90, 20], 5=>[500000]}
Or try 1 + Math.log10(n).floor if you need the keys to be the actual number of digits.
I have thought of a couple of different ways to generate the following array: [1, 10, 100, 1_000, 10_000, 100_000, 1_000_000]
It seems like it might be possible to generate this array with the step function in an elegant manner, but I was not able to figure it out. Something that passes in a second argument to the step function and says you want the last value times 10:
0.step(1_000_000, ???).to_a
Here are the solutions I have come up with so far:
I don't really like the inject solution because I would prefer to specify 1_000_000 as the upper bound:
(0..6).inject([]) { |memo, number| memo << 10**number; memo }
This is the ugly step solution I came up with:
result = []
0.step(6) {|number| result << 10 ** number}
result
A while loop does not feel right either, but at least it lets me specify the upper_bound (instead of Math.log10(upper_bound)):
result = [1]
while result.last < 1_000_000
result << result.last * 10
end
result
Thanks for the help.
You had many solutions. What about using map this way.
7.times.map { |i| 10**i }
#=> [1, 10, 100, 1000, 10000, 100000, 1000000]
If you want to set the upper bound you could always to something like this
1_000_000.to_s.size.times.map { |i| 10**i }
#=> [1, 10, 100, 1000, 10000, 100000, 1000000]
How about this?
0.upto(Math.log10(1_000_000)).map { |i| 10**i }
It's only going to properly work for powers of 10, but it lets you specify the upper bound, and then computes the powers of 10 to iterate through.
If you want to lead with the upper bound, you can do so easily via:
Math.log10(10_000_000).to_i.downto(0).map {|i| 10 ** i }.reverse
If terseness is really important, you can always reopen Fixnum with a generalized solution:
class Fixnum
def by_powers_of(base = 10)
0.upto(Math.log(self, base)).map {|i| base ** i }
end
end
10_000_000.by_powers_of(10)
# => [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000]
(64**2).by_powers_of(2)
# => [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096]
class Integer
def powers_upto(max)
results = []
exp = 0
loop do
result = self**exp
break if result > max
results << result
exp += 1
end
results
end
end
p 10.powers_upto(1_000_000)
p 2.powers_upto(11)
--output:--
[1, 10, 100, 1000, 10000, 100000, 1000000]
[1, 2, 4, 8]