Is there a good way to calculate sum of range elements in ruby - ruby

What is the good way to calculate sum of range?
Input
4..10
Output
4 + 5 + 6 + 7 + 8 + 9 + 10 = 49

You can use Enumerable methods on Range objects, in this case use Enumerable#inject:
(4..10).inject(:+)
#=> 49
Now, in Ruby 2.4.0 you can use Enumerable#sum
(4..10).sum
#=> 49

I assume the ranges whose sums to to be computed are ranges of integers.
def range_sum(rng)
rng.size * (2 * rng.first + rng.size - 1) / 2
end
range_sum(4..10) #=> 49
range_sum(4...10) #=> 39
range_sum(-10..10) #=> 0
By defining
last = rng.first + rng.size - 1
the expression
rng.size * (2 * rng.first + rng.size - 1) / 2
reduces to
rng.size * (rng.first + last) / 2
which is simply the formula for the sum of values of an arithmetic progression. Note (4..10).size #=> 7 and (4...10).size #=> 6.

Use Enumerable#reduce:
range.reduce(0, :+)
Note that you need 0 as the identity value in case the range to fold is empty, otherwise you'll get nil as result.

(4..10).to_a * " + " + " = 15"
#=> 4 + 5 + 6 + 7 + 8 + 9 + 10 = 15
:)

YES! :)
(1..5).to_a.inject(:+)
And for visual representation
(1..5).to_a.join("+")+"="+(1..5).inject(:+).to_s

Related

The sum of all numbers less than 1000, multiples of 3 or 5

If we list all natural numbers less than 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all numbers less than 1000, multiples of 3 or 5.
I just started learning Ruby, I used to work only with C languages. Please explain why this code doesn't work. Thank you!!!
Code:
sum = 0;
i = 3;
while (i < 1000) do
if ((i % 3 == 0) || (i % 5 == 0))
sum += i;
end
end
puts "The sum of all the multiples of 3 or 5 below 1000: #{sum}"
And when I run the file, it loads indefinitely.
enter image description here
You are never incrementing i.
The while loop will terminate if: i >= 1000
But i = 3 and there is no i+=1 so this loop will never terminate.
#Raavgo has explained the problem with your code. If you are looking for a fast solution I suggest the following.
def tot(n, limit)
m, rem = limit.divmod(n)
m * (n + limit - rem)/2
end
tot(3, 999) + tot(5, 999) - tot(15, 999)
#=> 233168
The term tot(15, 999) is to compensate for double-counting of terms that are divisible by both 3 and 5.
See Numeric#divmod.
Suppose
n = 5
limit = 999
Then
m, rem = limit.divmod(n)
#=> [199, 4]
So
m #=> 199
rem #=> 4
Then we want to compute
5 + 10 + ... + 999 - rem
#=> 5 + 10 + ... + 995
This is simply the the sum of an arithmetic progression:
199 * (5 + 995)/2
which equals
m * (n + limit - rem)/2
(0..1000).select(&->(i){ (i % 3).zero? || (i % 5).zero? }).sum
(0..1000).filter { |i| i % 3 == 0 || i % 5 == 0 }.sum
your approach is fine if you increment i as said in the other answer, but a more idiomatic Ruby looks like this.

Find all natural numbers which are multiplies of 3 and 5 recursively

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.
def multiples_of(number)
number = number.to_f - 1.0
result = 0
if (number / 5.0) == 1 || (number / 3.0) == 1
return result = result + 5.0 + 3.0
elsif (number % 3).zero? || (number % 5).zero?
result += number
multiples_of(number-1)
else
multiples_of(number-1)
end
return result
end
p multiples_of(10.0)
My code is returning 9.0 rather than 23.0.
Using Core Methods to Select & Sum from a Range
It's not entirely clear what you really want to do here. This is clearly a homework assignment, so it's probably intended to get you to think in a certain way about whatever the lesson is. If that's the case, refer to your lesson plan or ask your instructor.
That said, if you restrict the set of possible input values to integers and use iteration rather than recursion, you can trivially solve for this using Array#select on an exclusive Range, and then calling Array#sum on the intermediate result. For example:
(1...10).select { |i| i.modulo(3).zero? || i.modulo(5).zero? }.sum
#=> 23
(1...1_000).select { |i| i.modulo(3).zero? || i.modulo(5).zero? }.sum
#=> 233168
Leave off the #sum if you want to see all the selected values. In addition, you can create your own custom validator by comparing your logic to an expected result. For example:
def valid_result? range_end, checksum
(1 ... range_end).select do |i|
i.modulo(3).zero? || i.modulo(5).zero?
end.sum.eql? checksum
end
valid_result? 10, 9
#=> false
valid_result? 10, 23
#=> true
valid_result? 1_000, 233_168
#=> true
There are a number of issues with your code. Most importantly, you're making recursive calls but you aren't combining their results in any way.
Let's step through what happens with an input of 10.
You assign number = number.to_f - 1.0 which will equal 9.
Then you reach the elsif (number % 3).zero? || (number % 5).zero? condition which is true, so you call result += number and multiples_of(number-1).
However, you're discarding the return value of the recursive call and call return result no matter what. So, your recursion doesn't have any impact on the return value. And for any input besides 3 or 5 you will always return input-1 as the return value. That's why you're getting 9.
Here's an implementation which works, for comparison:
def multiples_of(number)
number -= 1
return 0 if number.zero?
if number % 5 == 0 || number % 3 == 0
number + multiples_of(number)
else
multiples_of(number)
end
end
puts multiples_of(10)
# => 23
Note that I'm calling multiples_of(number) instead of multiples_of(number - 1) because you're already decrementing the input on the function's first line. You don't need to decrement twice - that would cause you to only process every other number e.g. 9,7,5,3
explanation
to step throgh the recursion a bit to help you understand it. Let's say we have an input of 4.
We first decrement the input so number=3. Then we hits the if number % 5 == 0 || number % 3 == 0 condition so we return number + multiples_of(number).
What does multiples_of(number) return? Now we have to evaluate the next recursive call. We decrement the number so now we have number=2. We hit the else block so now we'll return multiples_of(number).
We do the same thing with the next recursive call, with number=1. This multiples_of(1). We decrement the input so now we have number=0. This matches our base case so finally we're done with recursive calls and can work up the stack to figure out what our actual return value is.
For an input of 6 it would look like so:
multiples_of(6)
\
5 + multiples_of(5)
\
multiples_of(4)
\
3 + multiples_of(3)
\
multiples_of(2)
\
multiples_of(1)
\
multiples_of(0)
\
0
The desired result can be obtained from a closed-form expression. That is, no iteration is required.
Suppose we are given a positive integer n and wish to compute the sum of all positive numbers that are multiples of 3 that do not exceed n.
1*3 + 2*3 +...+ m*3 = 3*(1 + 2 +...+ m)
where
m = n/3
1 + 2 +...+ m is the sum of an algorithmic expression, given by:
m*(1+m)/2
We therefore can write:
def tot(x,n)
m = n/x
x*m*(1+m)/2
end
For example,
tot(3,9) #=> 18 (1*3 + 2*3 + 3*3)
tot(3,11) #=> 18
tot(3,12) #=> 30 (18 + 4*3)
tot(3,17) #=> 45 (30 + 5*3)
tot(5,9) #=> 5 (1*5)
tot(5,10) #=> 15 (5 + 2*5)
tot(5,14) #=> 15
tot(5,15) #=> 30 (15 + 3*5)
The sum of numbers no larger than n that are multiple of 3's and 5's is therefore given by the following:
def sum_of_multiples(n)
tot(3,n) + tot(5,n) - tot(15,n)
end
- tot(15,n) is needed because the first two terms double-count numbers that are multiples of 15.
sum_of_multiples(9) #=> 23 (3 + 6 + 9 + 5)
sum_of_multiples(10) #=> 33 (23 + 2*5)
sum_of_multiples(11) #=> 33
sum_of_multiples(12) #=> 45 (33 + 4*3)
sum_of_multiples(14) #=> 45
sum_of_multiples(15) #=> 60 (45 + 3*5)
sum_of_multiples(29) #=> 195
sum_of_multiples(30) #=> 225
sum_of_multiples(1_000) #=> 234168
sum_of_multiples(10_000) #=> 23341668
sum_of_multiples(100_000) #=> 2333416668
sum_of_multiples(1_000_000) #=> 233334166668

Finding number representation in different bases

I was recently solving a problem when I encountered this one: APAC Round E Q2
Basically the question asks to find the smallest base (>1) in which if the number (input) is written then the number would only consist of 1s. Like 3 if represented in base 2 would become 1 (consisting of only 1s).
Now, I tried to solve this the brute force way trying out all bases from 2 till the number to find such a base. But the constraints required a more efficient one.
Can anyone provide some help on how to approach this?
Here is one suggestion: A number x that can be represented as all 1s in a base b can be written as x = b^n + b^(n-1) + b^(n-2) + ... + b^1 + 1
If you subtract 1 from this number you end up with a number divisble by b:
b^n + b^(n-1) + b^(n-2) + ... + b^1 which has the representation 111...110. Dividing by b means shifting it right once so the resulting number is now b^(n-1) + b^(n-2) + ... + b^1 or 111...111 with one digit less than before. Now you can repeat the process until you reach 0.
For example 13 which is 111 in base 3:
13 - 1 = 12 --> 110
12 / 3 = 4 --> 11
4 - 1 = 3 --> 10
3 / 3 = 1 --> 1
1 - 1 = 0 --> 0
Done => 13 can be represented as all 1s in base 3
So in order to check if a given number can be written with all 1s in a base b you can check if that number is divisble by b after subtracting 1. If not you can immediately start with the next base.
This is also pretty brute-forcey but it doesn't do any base conversions, only one subtraction, one divisions and one mod operation per iteration.
We can solve this in O( (log2 n)^2 ) complexity by recognizing that the highest power attainable in the sequence would correspond with the smallest base, 2, and using the formula for geometric sum:
1 + r + r^2 + r^3 ... + r^(n-1) = (1 - r^n) / (1 - r)
Renaming the variables, we get:
n = (1 - base^power) / (1 - base)
Now we only need to check power's from (floor(log2 n) + 1) down to 2, and for each given power, use a binary search for the base. For example:
n = 13:
p = floor(log2 13) + 1 = 4:
Binary search for base:
(1 - 13^4) / (1 - 13) = 2380
...
No match for power = 4.
Try power = 3:
(1 - 13^3) / (1 - 13) = 183
(1 - 6^3) / (1 - 6) = 43
(1 - 3^3) / (1 - 3) = 13 # match
For n around 10^18 we may need up to (floor(log2 (10^18)) + 1)^2 = 3600 iterations.

Ruby - Sum Results of Select()

I'm doing www.eulerproject.net, the first problem:
If we list all the natural numbers below 10, that are multiples of 3
or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find
the sum of all the multiples of 3 or 5 below 1000.
The following is the code I have so far.
(3..999).to_a.select do |x|
x % 3.0 == 0 || x % 5.0 == 0
end
It would be easy to append the numbers into an array, but how can this be done by how can this be done by chaining a method onto the end of this. Something like
p start loop
do stuff
end.sum
To answer the question - yes, you can chain the method like you've shown.
(3..999).to_a.select do |x|
x % 3 == 0 || x % 5 == 0 # you don't have to use floats here, integers would work
end.inject(:+)
#=> 233168
The rule of a style guides is to NOT to chain methods to multiline do end blocks, but it is a working code.
It's the same as writing
(3..999).to_a.select { |x| x % 3 == 0 || x % 5 == 0 }.inject(:+)
#=>233168
Array#sum is an ActiveSupport method, not Ruby's, but I think you should use Ruby's methods in eulerproject tasks.
You are summing arithmetic series, so there is no need to iterate:
def sum(n,m)
p = n/m
m*p*(1+p)/2
end
n = 999
sum(n,3) + sum(n,5) - sum(n,15)
#=> 233168
Consider:
n = 100
m = 3
p = 100/3 #=> 33
sum(100,3) = 3 + 6 + 9 +...+ 99
= 3 * (1 + 2 +...+ p)
= 3 * p(1+p)/2
We need to subtract sum(100,15) because sum(100,3) + sum(100,5) double-counts:
sum(100,15) = 15 + 30 + 45 + 60 + 75 + 90
if you want to get the sum of array, you can do like this:
(3..999).inject(0) { |sum, e| e % 3 == 0 || e % 5 == 0 ? sum += e : sum }
=> 233168
it just need once loop.
You can omit the to_a, since calling 'select' to (3..999) will still return an array regardless.
Andrey's answer is the most compact one with :
(3..999).select{ |x| x % 3 == 0 || x % 5 == 0 }.inject(:+)

Is there a Ruby method to grab the ones/tenths/hundredths place for an integer?

I'm doing a Ruby kata that asks me to find the sum of the digits of all the numbers from 1 to N (both ends included).
So if I had these inputs, I would get these outputs:
For N = 10 the sum is 1+2+3+4+5+6+7+8+9+(1+0) = 46
For N = 11 the sum is 1+2+3+4+5+6+7+8+9+(1+0)+(1+1) = 48
For N = 12 the sum is 1+2+3+4+5+6+7+8+9+(1+0)+(1+1) +(1+2)= 51
Now I know in my head what needs to be done. Below is the code that I have to solve this problem:
def solution(n)
if n <= 9
return n if n == 1
solution(n-1) + n
elsif n >= 10
45 + (10..n) #How can I grab the ones,tenths, and hundreds?
end
end
Basically everything is fine until I hit over 10.
I'm trying to find some sort of method that could do this. I searched Fixnum and Integer but I haven't found anything that could help me. I want is to find something like "string"[0] but of course without having to turn the integer back in forth between a string and integer. I know that there is a mathematical relationship there but I'm having a hard time trying to decipher that.
Any help would be appreciated.
You can use modulo and integer division to calculate it recursively:
def sum_digits(n)
return n if n < 10
(n % 10) + sum_digits(n / 10)
end
sum_digits(123)
# => 6
A beginner would probably do this:
123.to_s.chars.map(&:to_i)
# => [1, 2, 3]
but a more thoughtful person would do this:
n, a = 123, []
until n.zero?
n, r = n.divmod(10)
a.unshift(r)
end
a
# => [1, 2, 3]
Rather than computing the sum of the digits for each number in the range, and then summing those subtotals, I have computed the total using combinatorial methods. As such, it is much more efficient than straight enumeration.
Code
SUM_ONES = 10.times.with_object([]) { |i,a| a << i*(i+1)/2 }
S = SUM_ONES[9]
def sum_digits_nbrs_up_to(n)
pwr = n.to_s.size - 1
tot = n.to_s.chars.map(&:to_i).reduce(:+)
sum_leading_digits = 0
pwr.downto(0).each do |p|
pwr_term = 10**p
leading_digit = n/pwr_term
range_size = leading_digit * pwr_term
tot += sum_leading_digits * range_size +
sum_digits_to_pwr(leading_digit, p)
sum_leading_digits += leading_digit
n -= range_size
end
tot
end
def sum_digits_to_pwr(d, p)
case
when d.zero? && p.zero?
0
when d.zero?
10**(p-1) * S * d * p
when p.zero?
10**p * SUM_ONES[d-1]
else
10**p * SUM_ONES[d-1] + 10**(p-1) * S * d * p
end
end
Examples
sum_digits_nbrs_up_to(456) #=> 4809
sum_digits_nbrs_up_to(2345) #=> 32109
sum_digits_nbrs_up_to(43021) #=> 835759
sum_digits_nbrs_up_to(65827359463206357924639357824065821)
#=> 10243650329265398180347270847360769369
These calculations were all essentially instantaneous. I verified the totals for the first three examples by straight enumeration, using #sawa's method for calculating the sum of digits for each number in the range.
Explanation
The algorithm can best be explained with an example. Suppose n equals 2345.
We begin by defining the following functions:
t(n) : sum of all digits of all numbers between 1 and n, inclusive (the answer)
sum(d): sum of all digits between 1 and d, inclusive, (for d=1..9, sum(d) = 0, 1, 3, 6, 10, 15, 21, 28, 36, 45).
g(i) : sum of digits of the number i.
f(i,j): sum of all digits of all integers between i and j-1, inclusive.
g(m) : sum of digits of the number m.
h(d,p): sum of all digits of all numbers between 0 and d*(10^p)-1 (derived below).
Then (I explain the following below):
t(2345) = f(0-1999)+f(2000-2299)+f(2300-2339)+f(2340-2344)+g(2345)
f( 0-1999) = h(2,3) = h(2,3)
f(2000-2299) = 2 * (2299-2000+1) + h(3,2) = 600 + h(3,2)
f(2300-2339) = (2+3) * (2339-2300+1) + h(4,1) = 200 + h(4,1)
f(2340-2344) = (2+3+4) * (2344-2340+1) + h(5,0) = 45 + h(5,0)
g(2345) = 2+3+4+5 = 14
so
t(2345) = 859 + h(2,3) + h(3,2) + h(4,1) + h(5,0)
First consider f(2000-2299). The first digit, 2, appears in every number in the range (2000..2299); i.e., 300 times. The remaining three digits contribute (by definition) h(3,2) to the total:
f(2000-2299) = 2 * 300 + h(3,2)
For f(2300-2339) the first two digits, 2 and 3, are present in all 40 numbers in the range (2300..2339) and the remaining two digits contribute h(4,1) to the total:
f(2300-2339) = 5 * 40 + h(4,1)
For f(2340-2344), the first three digits, '2,3and4, are present in all four number in the range ``(2340-2344) and the last digit contributes h(5,0) to the total.
It remains to derive an expression for computing h(d,p). Again, this is best explained with an example.
Consider h(3,2), which is the sum of the all digits of all numbers between 0 and 299.
First consider the sum of digits for the first digit. 0, 1 and 2 are each the first digit for 100 numbers in the range 0-299. Hence, the first digit, summed, contributes
0*100 + 1*100 + 2*100 = sum(2) * 10^2
to the total. We now add the sum of digits for the remaining 2 digits. The 300 numbers each have 2 digits in the last two positions. Each of the digits 0-9 appears in 1/10th of 2 * 300 = 600 digits; i.e, 60 times. Hence, the sum of all digits in last 2 digit positions, over all 300 numbers, equals:
sum(9) * 2 * 300 / 10 = 45 * 2 * 30 = 2700.
More generally,
h(d,p) = sum(d-1) * 10**p + sum(9) * d * p * 10**(p-1) if d > 0 and p > 0
= sum(d-1) * 10**p if d > 0 and p == 0
= sum(9) * d * p * 10**(p-1) if d == 0 and p > 0
= 0 if d == 0 and p == 0
Applying this to the above example, we have
h(2,3) = sum(1) * 10**3 + (45 * 2 * 3) * 10**2 = 1 * 1000 + 270 * 100 = 28000
h(3,2) = sum(2) * 10**2 + (45 * 3 * 2) * 10**1 = 3 * 100 + 270 * 10 = 3000
h(4,1) = sum(3) * 10**1 + (45 * 4 * 1) * 10**0 = 6 * 10 + 180 * 1 = 240
h(5,0) = sum(4) * 10**0 = 10 * 1 = 10
Therefore
t(2345) = 859 + 28000 + 3000 + 240 + 10 = 32109
The code above implements this algorithm in a straightforward way.
I confirmed the results for the first three examples above by using using #sawa's code to determine the sum of the digits for each number in the range and then summed those totals:
def sum_digits(n)
a = []
until n.zero?
n, r = n.divmod(10)
a.unshift(r)
end
a.reduce(:+)
end
def check_sum_digits_nbrs_up_to(n)
(1..n).reduce(0) {|t,i| t + sum_digits(i) }
end
check_sum_digits_nbrs_up_to(2345) #=> 32109

Resources