patternrubyMinor
Counting numbers whose digits all go up or down
Viewed 0 times
countingwhosealldigitsnumbersdown
Problem
I have created a program which takes a value
This has then been used as the maximum number of a range
Using the values in this array, I want to find the total number of increasing and decreasing integers within this range. These are integers containing digits that either ascend or descend with each proceeding digit.
For example, if
then
Then numbers like
The
My problem is as the powers of ten increase with each method call at the end of the program, it gets slower and slower to return the end result until it calls
x and uses this value to create a power of ten value like so 10 ** x. This has then been used as the maximum number of a range
1..(10 ** x), which has been expanded using the splat * method to create an array of numbers, and then assigned to the variable num_array.Using the values in this array, I want to find the total number of increasing and decreasing integers within this range. These are integers containing digits that either ascend or descend with each proceeding digit.
For example, if
x = 3then
num_array = [*1..(10**3)] #=> num_array = [1, 2, 3, 4, .. 998, 999, 1000]Then numbers like
234 which is ascending and 987 which is descending should be counted. Numbers like 555 fall into both categories so also should be counted but numbers like 482 should not because it doesn't follow either rule. The
each method is used to evaluate which integers follow this rule in the range. My problem is as the powers of ten increase with each method call at the end of the program, it gets slower and slower to return the end result until it calls
total_nums(6) which then takes too long.- Is there a general rule of thumb to help process really large arrays like this so it's much faster for your program to return the end result?
- What would you say are your preferred methods for such an approach like this?
- And would something like Memoization work here?
def total_nums(x)
return 0 if x == nil
return 1 if x == 0
num = 10 ** x
num_array = [*1..num]
total = 0
num_array.each do |i|
if i == i.to_s.split("").sort.join.to_i || i == i.to_s.split("").sort.reverse.join.to_i
total +=1
end
end
return total
end
total_nums(0) #=> 1
total_nums(1) #=> 10
total_nums(2) #=> 100
total_nums(3) #=> 475
total_nums(4) #=> 1675
total_nums(5) #=> 4954
total_nums(6) #=> 12952Solution
To make Ruby internally use a loop instead of an Array you may want to use
But I doubt the "HUGE array" is the performance issue here.
Then conversions between Integer and String seem to be unnecessary:
Note: probably you want either return 0 if x == 0 or start the loop from 0, not 1.
1.upto(10 ** x) that is an Enumerator. But I doubt the "HUGE array" is the performance issue here.
- First of all Ruby says to do
total = .count{ ... }instead oftotal = 0; .each{ total += 1 if ... }
- Then do this thing only once and store in a variable
t = i.to_s.split("").sort-- x2 faster
- Then use
.charsinstead of.split("")-- x4 faster
Then conversions between Integer and String seem to be unnecessary:
def total_nums x
return 0 if x == nil
return 1 if x == 0
1.upto(10 ** x).count do |i|
s = i.to_s.chars
t = s.sort
s == t || s == t.reverse
end
endNote: probably you want either return 0 if x == 0 or start the loop from 0, not 1.
Code Snippets
def total_nums x
return 0 if x == nil
return 1 if x == 0
1.upto(10 ** x).count do |i|
s = i.to_s.chars
t = s.sort
s == t || s == t.reverse
end
endContext
StackExchange Code Review Q#123127, answer score: 2
Revisions (0)
No revisions yet.