Question

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.

Était-ce utile?

La 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

Autres conseils

perhaps the error is because the temp_array hasn't been instantiated (I don't see the creation of temp_array in your code example). If, however, the problem is like @jethroo states above, and you have a nil value in your array, you can add a check for nil on each element before evaluating .to_i on it:

array.map{|x| 
  if x.nil?
    puts 'element is nil, moving on...'
  else
    x.to_i <= 10 ? 1 : 2
}

This can be done in one line in ruby:

array.map{|x| x.to_i <= 10 ? 1 : 2}

1.9.3-p194 :003 > a = [*0..20]
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] 
1.9.3-p194 :004 > a.map{|x| x <= 10 ? 1 : 2}
=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top