简体   繁体   中英

iterate over array to find int over 10 and add those two digits together

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM