質問

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.

役に立ちましたか?

解決

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

他のヒント

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] 
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top