1

I have an array of integers, and I am attempting to multiply every second element by 2 moving backwards in the array. However, it does not seem to accept the * operator on the array item, results in the error message: undefined method `*' for nil:NilClass (NoMethodError)

 index = array.length
  while index > 0
    array[index] * 2
    index - 2
  end

I have checked the class of the array items and it is indeed an integer, so I am unsure why this does not work.

Thanks.

5
  • 4
    You're not doing anything with the value of your array[index] * 2 and index - 2 expressions, you need to assign them to something: array[index] *= 2, array[index] = array[index] * 2, index = index - 2, index -= 2, ... Commented Apr 13, 2019 at 17:15
  • tried doing that, still results in " undefined method `*' for nil:NilClass (NoMethodError)" Commented Apr 13, 2019 at 17:18
  • it is an array of integers: [4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2] Commented Apr 13, 2019 at 17:33
  • 2
    your index should be array.length - 1 (remember, arrays are 0-indexed). Also you are not doing anything with array[index] * 2 (either print it, or assign to a variable) Commented Apr 13, 2019 at 18:27
  • With an input array of [4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2], what did you expect the output to be? I had interpreted the phrase "every second element" to mean the result should be [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]. Is that right? Commented Apr 13, 2019 at 19:16

4 Answers 4

1

If you fix the indexing as others have suggested, and change the third and fourth lines to actually modify the array and index variables, then your code works as intended for any array with an even number of elements.

index = array.length - 1
while index > 0
  array[index] *= 2
  index -= 2
end

# array now =='s [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]

Alternatively, you could perform the operation in one line using map.with_index by taking advantage of the fact that every second element of an array will have an index that is an odd number.

array.map.with_index { |n, i| i.odd? ? n * 2 : n }
# Or if you prefer,
array.map.with_index { |n, i| if i.odd? then n * 2 else n end }

#=> [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
Sign up to request clarification or add additional context in comments.

Comments

1

You can iterate reversed array with indexes, and then reverse result Array#reverse i % 3 is used to multiply each 3rd element.

Error undefined method *' for nil:NilClass (NoMethodError) in your example appears because array.length is 16(elements in array), but indexes starts from 0, so last index is 15, and in the first iteration you are trying to access array[16] that does not exist, so it is nil

array = [4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2]
result = array.reverse.each_with_index.map do |x, i|
  (i % 3).zero? ? x * 2 : x
end.reverse
# p result
#=> [8, 2, 4, 4, 4, 2, 8, 2, 4, 4, 4, 2, 8, 2, 4, 4]

UPDATE: Sekalf Nroc's answer is good with odd? if you need each 2nd element to multiply, but if you had for example 15 elements, you could see unexpected results, so reverse still needed to walk array backwards, by combining those approaches, you can do something like this:

array = [4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 99]
p array.map.with_index { |n, i| i.odd? ? n * 2 : n } # WRONG RESULT
#=>[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 99]
p array.reverse.map.with_index { |n, i| i.even? ? n * 2 : n }.reverse
#=>[8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 198]

Comments

0

Another approach, that uses Numeric#step. It works good with all the examples even with another step(array3)

array1 = [4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2]
array2 = [2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2]
array3 = [2, 4, 4, 2, 4, 4, 2, 4, 4, 2, 4, 4, 2, 4, 4, 2]

(array1.size - 1).step(0, -2).each { |i| array1[i] *= 2 }
(array2.size - 1).step(0, -2).each { |i| array2[i] *= 2 }
(array3.size - 1).step(0, -3).each { |i| array3[i] *= 2 }

p array1, array2, array3
#=>[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
#=>[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
#=>[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]

Comments

0

You could use a Range, which provides the Range#step method. For example, given the array:

ary = [4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2]

This is a way for "multiply every second element by 2 moving backwards in the array" using Array#reverse_each:

(1...ary.size).step(2).each { |i| ary.size.odd? ? ary[i] *=2 : ary[i-1] *=2 }
#=> [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]

Note that the first part (1...ary.size).step(2).to_a returns the odd indexes:

#=> [1, 3, 5, 7, 9, 11, 13, 15]

Also note the three points ... in range.

For ary = [2, 4, 2] #=> [2, 8, 2]

For ary = [2, 4, 2, 4] #=> [4, 4, 4, 4]

3 Comments

Nice approach, but its not a universal solution, try with [2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2]
@YuriyVerbitskiy, thanks. Fixed, I misinterpreted the OP. Even if I have one more doubt.
I tried Numeric#step and added a new answer, it looks like better way for use it in this case

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.