Search code examples
rubyarraysloopsblockevaluate

Evaluating an array in Ruby


I'm trying to evaluate each position in an array and assign a new value to that position if it falls within a certain range. Here is my method code and method call:

def array_eval array
    array.each do |x|
        if x.to_i <= 10
            array[x] = 1
        else
            array[x] = 2
        end
    end
end

array_eval temp_array
puts temp_array

And here is my output error from the terminal:

carwashalgorithm.rb:109:in `[]=': no implicit conversion from nil to integer (TypeError)

from carwashalgorithm.rb:109:in `block in array_eval'
from carwashalgorithm.rb:107:in `each'
from carwashalgorithm.rb:107:in `array_eval'
from carwashalgorithm.rb:117:in `<main>'

I can do this with control flow, but I know there is an easier way to evaluate all of these values using a block. This is what I'm trying to do with the above. Any and all help is appreciated.


Solution

  • Your each loop calls the given block for each element, passing that element:

    array.each do |x| # <- x is a reference to an element
      # ...
    end
    

    Inside the loop you call Array#[]= with that element:

      array[x] = 1    # <- the same x
    

    This doesn't work (it raises the TypeError), you have to pass the element's index.

    You could use Array#each_index - it passes the index instead of the element itself:

    def array_eval(array)
      array.each_index do |x|
        if array[x].to_i <= 10
          array[x] = 1
        else
          array[x] = 2
        end
      end
    end
    

    Or Array#map! - it replaces the element with the value returned by the block:

    def array_eval(array)
      array.map! do |item|
        if item <= 10
          1
        else
          2
        end
      end
    end
    

    The above can be written as a one-liner (see jethroo's answer):

    def array_eval(array)
      array.map! { |item| item <= 10 ? 1 : 2 }
    end