Trying to iterate over and array and for any digit 10 or higher, split those digits and add them together for instance: 10 > "1" "0" > 1
.
I am able to iterate through the array and achieve that. however, it returns nil
instead of the digits < 9
.
def over_ten_sum
#splits the numbers over 10 into seperate digit and sums them
square_odd.map do |num|
if num > 9
num.to_s.chars.each_slice(2).map { |num_1, num_2| num_1.to_i + num_2.to_i }
end
end
end
With a value of [6, 4, 10, 2, 14, 7, 8, 4, 6, 7, 18, 4]
it returns:
=> [nil, nil, [1], nil, [5], nil, nil, nil, nil, nil, [9], nil]
I am trying to have the output be [6, 4, 1, 2, 5, 7, 8, 6, 7, 9, 4]
Just not seeing the disconnect here. Thank you in advance for any insights.
Suppose you were to write
[1, 2, 3].map { |n| }
#=> [nil, nil, nil]
An array of nil
s is returned because map
returns nil
for n
if n
is not assigned a value in the block. Similarly,
[1, 2, 3].map { |n| 2*n if n > 1 }
#=> [nil, 4, 6]
which is very similar to the problem with the OP's code. If one doesn't want nil
s in the array returned one simply needs to map each element of the array into a non-nil value:
[1, 2, 3].map { |n| n > 1 ? 2*n : n }
#=> [1, 4, 6]
Now let's look at the line
num.to_s.chars.each_slice(2).map { |num_1, num_2| num_1.to_i + num_2.to_i }
If num = 34
, this returns [7]
, which, except for the fact that 7
is in an array, is correct. On the other hand, if num = 134
the expression returns [4, 4]
(ie, [1+3, 4]
), which I don't expect is what is wanted. If, however, the numbers always have two digits, the above expression is the same as:
num[0].to_i + num[1].to_i
which is much simpler. 1 To make it more general you need to write something like the following 2 :
def over_nine_sum(arr)
arr.map { |n| n > 9 ? n.to_s.each_char.reduce(0) { |t,s| t + s.to_i } : n }
end
over_nine_sum [12, 5, 71, 3]
#=> [3, 5, 8, 3]
See Enumerable#reduce (aka inject
).
@JörgWMittag noted (see comment) that the sum of the digits of a single-digit number ( 0-9
) is the same as the number itself, so there is no need to treat those numbers differently. We may therefore write
def sum_digits(arr)
arr.map { |n| n.to_s.each_char.reduce(0) { |t,s| t + s.to_i } }
end
sum_digits [12, 5, 71, 3]
#=> [3, 5, 8, 3]
As @steenslag's suggested in a comment, this can be simplified to
def sum_digits(arr)
arr.map { |n| n.digits.sum }
end
which uses the methods Integer#digits and Array#sum (both new in Ruby v2.4).
Consider the steps (for the first version of sum_digits
above) when n = 34
:
n.to_s.each_char.reduce(0) { |t,s| t + s.to_i }
#=> 34.to_s.each_char.reduce(0) { |t,s| t + s.to_i }
#=> "34".each_char.reduce(0) { |t,s| t + s.to_i }
Now reduce
initializes the block variable t
(the "memo", which is returned) to zero and passes the first digit of "34"
to the block and assigns it to the block variable s
:
t = 0
s = "3"
The block calculation is:
t + s.to_i
#=> 0 + "3".to_i
#=> 3
which is the updated value of t
. Next,
s = "4"
t + s.to_i
#=> 3 + "4".to_i
#=> 3 + 4
#=> 7
1. Another problem is that if square_odd
is a local variable, Ruby will raise an "undefined variable or method" exception when it evaluates it.
2. n.to_s.each_char.reduce(0)...
is preferable to n.to_s.chars.reduce(0)...
because chars
returns a temporary array whereas each_char
returns an enumerator.
Remove the if
:
def over_ten_sum
#splits the numbers over 10 into seperate digit and sums them
square_odd.map do |num|
num.to_s.chars.each_slice(2).map { |num_1, num_2| num_1.to_i + num_2.to_i }
end.flatten
end
#=> [6, 4, 1, 2, 5, 7, 8, 4, 6, 7, 9, 4]
What was wrong? if num > 9
left out every other number from being treated and nothing was returned, so you got nil
each time. To make it clearer, check the following code:
def over_ten_sum
#splits the numbers over 10 into seperate digit and sums them
square_odd.map do |num|
if num > 9
num.to_s.chars.each_slice(2).map { |num_1, num_2| num_1.to_i + num_2.to_i }
else
num
end
end.flatten
end
#=> [6, 4, 1, 2, 5, 7, 8, 4, 6, 7, 9, 4]
As you can see, the result is the same, because else
send num
back as it is when it is not greater than 9.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.