Forum: Ruby newbie adding to array question

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
D13563098fc07b07400f833c4e6e7169?d=identicon&s=25 Roger Reeks (cogrady2k)
on 2008-10-16 16:50
hi, i have the following code in my project


def next_seq

  x = @current + @previous

  @previous = @current

  @current = x

end



def display_all

        count = 2
while count < @iteration

  next_seq

        count = count + 1
  puts @current

  end

end



ive been trying to add the result each time the result is calculated to
array but keep getting stuck

my idea was puttting @fibresults[count] = @current in the while loop,
but i keep getting nil when i try and access it later on

thanks for any help
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2008-10-16 17:26
(Received via mailing list)
On 16.10.2008 16:50, Roger Reeks wrote:
>
>
> array but keep getting stuck
>
> my idea was puttting @fibresults[count] = @current in the while loop,
> but i keep getting nil when i try and access it later on

You should disclose more of your code so we can see where it does not
work.  There is no @fibresults in the code above so we cannot know what
went wrong.

Cheers

  robert
D13563098fc07b07400f833c4e6e7169?d=identicon&s=25 Roger Reeks (cogrady2k)
on 2008-10-16 17:36
@fibresults= []

def initialize


 @iterations = 10

 @previous = 1

 @current = 1

 @fibresults[0] =@previous

 @fibresults[1] =@current


end

 def next_seq

   x = @current + @previous

   @previous = @current

   @current = x

 end



 def display_all

         count = 2
 while count < @iteration

   next_seq

         count = count + 1
      @fibresults[count] = @current
   puts @current

  end

 end
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2008-10-16 18:10
(Received via mailing list)
On 16.10.2008 17:36, Roger Reeks wrote:
>
>
>          count = 2
>  end
Here's how you can make your life easier: you do not need @previous and
@current.  Instead you only need the array.  Note that you can access
elements from the end, i.e. @fibresults[-1] and @fibresults[-2] access
the last and last but one elements.

Another simplification: the while loop can be replaced by

@iteration.times do |count|
end

or

2.upto @iteration - 1 do |count|
end

Kind regards

  robert
134ea397777886d6f0aa992672a50eaa?d=identicon&s=25 Mark Thomas (Guest)
on 2008-10-16 19:30
(Received via mailing list)
def fib(n)
  curr = 0
  succ = 1
  all = []

  n.times do
      curr, succ = succ, curr + succ
      all << curr
  end

  all
end

fib(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-10-16 21:53
Roger Reeks wrote:
>
> @fibresults= []
>
> def initialize

You don't want to define an initialize method at the top level - only
inside a class. If I run your code as posted, I get:
fib.rb:3: warning: redefining Object#initialize may cause infinite loop

So the first thing I do is to wrap all this in a class definition (and
tidy the formatting):

@fibresults= []

class Fib
  def initialize
    @iterations = 10
    @previous = 1
    @current = 1
    @fibresults[0] =@previous
    @fibresults[1] =@current
  end

  def next_seq
    x = @current + @previous
    @previous = @current
    @current = x
  end

  def display_all
    count = 2
    while count < @iteration
    next_seq
    count = count + 1
    @fibresults[count] = @current
    puts @current
   end
  end
end  # class Fib

f = Fib.new
f.display_all

Now it becomes clearer where the problem is:

fib.rb:8:in `initialize': undefined method `[]=' for nil:NilClass
(NoMethodError)
  from fib.rb:29:in `new'
  from fib.rb:29

You need to move the initialisation of @fibresults *inside* the
initialize method of the Fib class.

Next bug:

fib.rb:20:in `<': comparison of Fixnum with nil failed (ArgumentError)
  from fib.rb:20:in `display_all'
  from fib.rb:30

That's because you wrote "@iteration" in one place and "@iterations" in
another.  So I'll change the former to the latter.

At this point the code runs just fine, printing:

2
3
5
8
13
21
34
55

You don't actually make use of the values you stored in the array
though, so I'll add an accessor to show that they are correct. The code
now looks like this:

class Fib
  attr_reader :fibresults

  def initialize
    @iterations = 10
    @previous = 1
    @current = 1
    @fibresults= []
    @fibresults[0] =@previous
    @fibresults[1] =@current
  end

  def next_seq
    x = @current + @previous
    @previous = @current
    @current = x
  end

  def display_all
    count = 2
    while count < @iterations
    next_seq
    count = count + 1
    @fibresults[count] = @current
    puts @current
   end
  end
end  # class Fib

f = Fib.new
f.display_all
p f.fibresults

and the results:

2
3
5
8
13
21
34
55
[1, 1, nil, 2, 3, 5, 8, 13, 21, 34, 55]

Oops, an off-by-one error there. You should have assigned to
@fibresults[count] *before* incrementing count. You can just swap those
two lines around.

So now your code works. Of course, as others have shown, there are much
shorter ways of writing this in Ruby. However I think it's of good
educational value in the first place to get your own code working,
starting from the way you initially wrote it.
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-10-16 22:06
Incidentally, I was able to spot the errors very quickly without really
having to think, but ruby will help you if you run it with the -w flag:

ruby -w fib.rb

or

#!/usr/bin/ruby -w
... rest of code

This gives a number of warnings when dubious code runs, in particular it
would have told you where you had mistyped an instance variable name:

fib.rb:10: warning: instance variable @fibresults not initialized

fib.rb:22: warning: instance variable @iteration not initialized
D13563098fc07b07400f833c4e6e7169?d=identicon&s=25 Roger Reeks (cogrady2k)
on 2008-10-20 15:17
thanks for the help up to now, much appreciated

i want to modify the code so it can pu

1.is_fibonacci # returns true
2.is_fibonacci # returns true
3.is_fibonacci # returns false

how could i do that?

thanks again
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-10-20 17:19
Roger Reeks wrote:
> thanks for the help up to now, much appreciated
>
> i want to modify the code so it can pu
>
> 1.is_fibonacci # returns true
> 2.is_fibonacci # returns true
> 3.is_fibonacci # returns false
>
> how could i do that?

class Integer
  def is_fibonacci(x=1, y=1)
    ... put your code here
    ... the number you are testing is "self"
  end
end
134ea397777886d6f0aa992672a50eaa?d=identicon&s=25 Mark Thomas (Guest)
on 2008-10-20 17:25
(Received via mailing list)
> 1.is_fibonacci # returns true
> 2.is_fibonacci # returns true
> 3.is_fibonacci # returns false
>
> how could i do that?

Assuming you mean you want to see if a digit is in the answer (in
which case 3 would actually return true), you can do this:

class Fixnum
  def fibonacci?(n=10)
    fib(n).include? self
  end
end

puts 3.fibonacci?
#=> true
puts 4.fibonacci?
#=> false

-- Mark.
D13563098fc07b07400f833c4e6e7169?d=identicon&s=25 Roger Reeks (cogrady2k)
on 2008-10-20 17:52
Thanks for the help guy, really appreciate it, im really getting into
ruby

Thanks again
This topic is locked and can not be replied to.