Strange error in ruby 1.9.1

Hello all,

I just compiled ruby 1.9.1 from source on my computer (osx snow
leopard), and I'm going through the old ruby quiz exercises for fun. I'm
on the secret santa one, and I wrote the code that determines that each
persons secret santa does not have the same last name, to ensure that
each person has to get a gift for someone from a different family. The
quiz is listed here:

http://rubyquiz.com/quiz2.html

My code runs fine most of the time. However, occasionally I'll get a
strange "undefined method" error. See the code below and sample output:

class Person
  attr_accessor :first, :last, :recipient
  def initialize(first, last)
    @first = first
    @last = last
    @recipient = nil
  end
end

a = [ giant listing of names in the format of "first last" ]

santa_array = [] # instantiate an empty array
a.each do |full_name|
  split_array = full_name.split
  my_person = Person.new(split_array[0], split_array[1])
  santa_array.push(my_person)
end

recipient_array = Array.new(santa_array)
santa_array.shuffle!
recipient_array.shuffle!

santa_array.each do |element|
  index = 0
  while element.recipient == nil
    if element.last != recipient_array[index].last # if the last names
are different, process
      element.recipient = recipient_array[index]
      recipient_array.delete_at(index)
    else
      index += 1 # else the last names are the same, loop again on index
+= 1
    end
  end
end

santa_array.each { |element| puts "#{element.first} #{element.last},
recipient == #{element.recipient.first} " +
                  "#{element.recipient.last}" }
puts "\n\n"
puts "santa_array.count == #{santa_array.count}"
puts "recipient_array.count == #{recipient_array.count}"

And here's some sample output:
brandentanga$ ./secretSanta.rb
./secretSanta.rb:67:in `block in <main>': undefined method `last' for
nil:NilClass (NoMethodError)
  from ./secretSanta.rb:64:in `each'
  from ./secretSanta.rb:64:in `<main>'
brandentanga$ ./secretSanta.rb
luke skywalker, recipient == lando calrissian
darth vader, recipient == han solo
anakin skywalker, recipient == jeanluc piccard
... so on and so forth, continuing to print properly...

As you can see from the above output, I ran my code twice, with no
modifications, all names are hard coded, and guaranteed to have first
and last names separated by a space. So how can the same code with the
same input produce a runtime error, then on the next run process as
expected?

···

--
Posted via http://www.ruby-forum.com/.

And here's some sample output:
brandentanga$ ./secretSanta.rb
./secretSanta.rb:67:in `block in <main>': undefined method `last' for
nil:NilClass (NoMethodError)

bug maybe? try trunk and see if it does the same...
-rp

···

--
Posted via http://www.ruby-forum.com/\.

You don't check that index < recipient_array.size so if enough last names
match recipient_array[index] will be out of bounds. In Ruby Array.
returns nil for out of bounds indices. To answer your exact question the
random order given by shuffle! will be different each time you run the
program so although the input is the same the result of your algorithm is
not.

···

On Tue, 18 May 2010 00:52:31 +0900, Branden Tanga <branden.tanga@gmail.com> wrote:

Hello all,

I just compiled ruby 1.9.1 from source on my computer (osx snow
leopard), and I'm going through the old ruby quiz exercises for fun. I'm
on the secret santa one, and I wrote the code that determines that each
persons secret santa does not have the same last name, to ensure that
each person has to get a gift for someone from a different family. The
quiz is listed here:

Ruby Quiz - Secret Santas (#2)

My code runs fine most of the time. However, occasionally I'll get a
strange "undefined method" error. See the code below and sample output:

class Person
  attr_accessor :first, :last, :recipient
  def initialize(first, last)
    @first = first
    @last = last
    @recipient = nil
  end
end

a = [ giant listing of names in the format of "first last" ]

santa_array = # instantiate an empty array
a.each do |full_name|
  split_array = full_name.split
  my_person = Person.new(split_array[0], split_array[1])
  santa_array.push(my_person)
end

recipient_array = Array.new(santa_array)
santa_array.shuffle!
recipient_array.shuffle!

santa_array.each do |element|
  index = 0
  while element.recipient == nil
    if element.last != recipient_array[index].last # if the last names
are different, process
      element.recipient = recipient_array[index]
      recipient_array.delete_at(index)
    else
      index += 1 # else the last names are the same, loop again on index
+= 1
    end
  end
end

santa_array.each { |element| puts "#{element.first} #{element.last},
recipient == #{element.recipient.first} " +
                  "#{element.recipient.last}" }
puts "\n\n"
puts "santa_array.count == #{santa_array.count}"
puts "recipient_array.count == #{recipient_array.count}"

And here's some sample output:
brandentanga$ ./secretSanta.rb
./secretSanta.rb:67:in `block in <main>': undefined method `last' for
nil:NilClass (NoMethodError)
  from ./secretSanta.rb:64:in `each'
  from ./secretSanta.rb:64:in `<main>'
brandentanga$ ./secretSanta.rb
luke skywalker, recipient == lando calrissian
darth vader, recipient == han solo
anakin skywalker, recipient == jeanluc piccard
... so on and so forth, continuing to print properly...

As you can see from the above output, I ran my code twice, with no
modifications, all names are hard coded, and guaranteed to have first
and last names separated by a space. So how can the same code with the
same input produce a runtime error, then on the next run process as
expected?

--
Alex Gutteridge

Alex Gutteridge wrote:

You don't check that index < recipient_array.size so if enough last
names
match recipient_array[index] will be out of bounds. In Ruby Array.
returns nil for out of bounds indices. To answer your exact question the
random order given by shuffle! will be different each time you run the
program so although the input is the same the result of your algorithm
is
not.

Aaaah, that makes perfect sense. Thanks for the help.

···

--
Posted via http://www.ruby-forum.com/\.