Derek M
Derek M

Reputation: 29

Ruby undefined method '**'

I'm attempting to write a function that uses array methods to do a variety of things. I need to use the each method to print the cube of each element in the array. Here's my code.

def foo(a)

    a.each { |x| puts x ** 3 }

    a.each_slice(3) { |x| puts x }
    a.select do |x|

        if x%5 == 0
            puts x
        end
    end

    a.map { |x| x ** 3 }
    aa.inject(0) { |x, y| x * y }

end

a = Array.new(50)
a.each { |x| x = rand(10..100) }

foo(a)

I keep getting this error:

Traceback (most recent call last):
        3: from task2.rb:21:in `<main>'
        2: from task2.rb:3:in `foo'
        1: from task2.rb:3:in `each'
task2.rb:3:in `block in foo': undefined method `**' for nil:NilClass (NoMethodError)

Upvotes: 1

Views: 126

Answers (4)

Oleksandr Holubenko
Oleksandr Holubenko

Reputation: 4440

#each is just a simple iteration, it's doesn't modify the array. Instead of:

a = Array.new(50)
a.each { |x| x = rand(10..100) }

you can simply do this:

a = Array.new(50) { rand(10..100) }

Upvotes: 2

David Grayson
David Grayson

Reputation: 87516

You should use the Ruby p method to help you debug things. (p x is a shortcut puts x.inspect.)

So try running the following program:

a = Array.new(50)
a.each { |x| x = rand(10..100) }
p a

From the output of that program, you can see that your array just consists of 50 nils. So then your real question is: How do I initialize an array properly? The x argument to your block is not some kind of reference to a cell in the array, it is simply a copy of the value that was held in the array, so writing to x does not do anything to the array.

The simplest way that would work for your application is:

a = Array.new(50) { rand(10..100) }

You could also write it like this:

a = 50.times.map { rand(10..100) }

You could also initialize your array in a more manual way by appending to it 50 times:

a = []
50.times { a << rand(10..100) }

You could also use the []= method, which is the most general way to write to an array:

a = []
50.times { |i| a[i] = rand(10..100) }

It's worthwhile to know about each of these different ways to make an array.

Upvotes: 0

lacostenycoder
lacostenycoder

Reputation: 11226

You're not modifying your array of 50 nil values. Try map! instead.

a.map! { |x| x = rand(10..100) }

Not sure exactly what the rest of your code is supposed to do but this seems more likely it.

def foo(a)
  a.each { |x| puts x ** 3 }
  a.each_slice(3) { |x| puts x }
  a.each do |x| # not sure why you wanted select, does not make sense here
    if x % 5 == 0
      puts x
    end
  end

  a.map { |x| x ** 3 }
   .inject(0) { |x, y| x * y }
end

array = Array.new(50)
array.map! { |x| x = rand(10..100) }

foo(array)

Upvotes: 0

ruby_newbie
ruby_newbie

Reputation: 3285

This line:

a.each { |x| x = rand(10..100) }

doesn't do what you think it does. Each does not alter the original array. If you want to change the original values of a you need a map!.

irb(main):025:0> a = Array.new(50)
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
irb(main):026:0> a.each { |x| x = rand(10..100) }
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
irb(main):027:0> a
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
irb(main):028:0> a.map { |x| x = rand(10..100) }
=> [67, 34, 96, 50, 52, 68, 14, 88, 67, 19, 83, 40, 35, 98, 88, 98, 39, 73, 41, 60, 25, 47, 33, 73, 20, 41, 32, 19, 65, 67, 47, 14, 11, 67, 32, 32, 13, 36, 23, 100, 14, 10, 73, 20, 59, 94, 54, 25, 57, 28]
irb(main):029:0>
a
=> [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]

 a.map! { |x| x = rand(10..100) }
=> [97, 83, 52, 54, 22, 54, 39, 32, 42, 70, 84, 15, 69, 32, 28, 40, 50, 98, 66, 79, 25, 37, 97, 28, 30, 11, 98, 57, 73, 77, 99, 75, 72, 40, 67, 62, 87, 41, 58, 10, 88, 24, 98, 10, 31, 94, 53, 43, 98, 17]
irb(main):032:0> a
=> [97, 83, 52, 54, 22, 54, 39, 32, 42, 70, 84, 15, 69, 32, 28, 40, 50, 98, 66, 79, 25, 37, 97, 28, 30, 11, 98, 57, 73, 77, 99, 75, 72, 40, 67, 62, 87, 41, 58, 10, 88, 24, 98, 10, 31, 94, 53, 43, 98, 17]
irb(main):033:0>

Also the preferred way to do this is with a range IMO.

Upvotes: 2

Related Questions