Home > OS >  Why can't I modify the array outside of the .each method?
Why can't I modify the array outside of the .each method?

Time:12-24

def adjacent_sum(arr)
  narr = []
  arr.each.with_index do  |num, index|
    narr << (arr[index]   arr[index 1])
  end
  return narr
end

print adjacent_sum([3, 7, 2, 11])
#=> [10, 9, 13], because [ 3 7, 7 2, 2 11 ]

adjacent_sum([2, 5, 1, 9, 2, 4])
#=> [7, 6, 10, 11, 6], because [2 5, 5 1, 1 9, 9 2, 2 4]

I am trying to modify the narr based on input from the user. Basically trying to get all adjacent nums to sum and return a new array.

Write a method adjacent_sum that takes in an array of numbers and returns a new array containing the sums of adjacent numbers in the original array. See the examples.

I am new to Ruby and its way of thinking. I do not know which iteration method to use for this problem and I know there are many iteration methods. I COULD go the old route and just do a while loop but I want to understand the mechanics of the .each loop.

Here is the error message:

/tmp/file.rb:5:in ` ': nil can't be coerced into Integer (TypeError)
    from /tmp/file.rb:5:in `block in adjacent_sum'
    from /tmp/file.rb:3:in `each'
    from /tmp/file.rb:3:in `with_index'
    from /tmp/file.rb:3:in `adjacent_sum'
    from /tmp/file.rb:10:in `<main>'

CodePudding user response:

Your loop is iterating over every element of the list. Let's take your first example.

[3, 7, 2, 11]

Okay, we're iterating. First, we hit 3 (we're adding 7, because it's the next one). Next, we hit 7 (we're adding 2 to it). Third, we hit 2 (adding 11 to it). Finally, we hit 11, and what are we adding to it? We're adding arr[4], which doesn't exist, hence your error.

each (and all of its many variants) fundamentally operate on the notion that you're taking every element of the underlying list. In your case, you want all but the last element, since you need to be able to add a "next" element in order to perform the addition. You can explicitly skip over the last element like so

arr.each.with_index do  |num, index|
  if index < arr.size - 1
    narr << (arr[index]   arr[index 1])
  end
end

but that's hardly better than a straight while loop. The point of all of Ruby's enumerable methods is choosing the right tool for the job, and in this case, Ruby's Enumerable has just the tool. each_cons gives you a sliding window of collection of N adjacent elements. So we can write

def adjacent_sum(arr)
  arr.each_cons(2).map { |x, y| x   y }
end

This is the power of Ruby's Enumerable module. Once you have a high-level construct that understands iteration, it provides a ton of tools for intelligently iterating over data structures, and that's why it's beneficial over a plain while loop.

CodePudding user response:

def adjacent_sum(arr)
narr = []
l = arr.length
  
arr.each.with_index do  |num,index|
  if index < arr.size-1
  narr << arr[index]   arr[index 1]
  end
end
return narr
end

print adjacent_sum([3, 7, 2, 11]) #=> [10, 9, 13], because [ 3 7, 7 2, 2 11 ]
puts
print adjacent_sum([2, 5, 1, 9, 2, 4]) #=> [7, 6, 10, 11, 6], because [2 5, 5 1, 1 9, 9 2, 2 4]
puts
  • Related