On 11/12/2010 9:43 AM, Aaron Haas wrote:
> I'm trying to figure out how to sort objects in an array by one of their
> instance
> variables, in this case last name. The person class has a first name,
> last name, and an address object. The address book class is made up of
> an array of persons. How do I sort the array of persons in
> alphabetically by the persons last name instance fields. I added a
> getLastname method to the persons class, but I'm not sure on the logic.
> 
> [CODE]
> class Person
>     attr_accessor :fname, :lname, :address
> 
>     # initializer
>     def initialize
>         @fname = @lname = ""
>         # since address is an object
>         @address = Address.new
>     end
> 
>     # assign given values to Person object
>     def crPerson (aFname, aLname, aAddress)
>         @fname = aFname
>         @lname = aLname
>         @address = aAddress
>     end
> 
>     def get_lname
>         return @lname
>     end

First of all, you don't need the get_lname method.  Use Person#lname
instead which was created when you called attr_accessor above.  It's
equivalent.

>      # string representation of Person
>      # note the syntax: address.to_s (to call the to_s instance method
> of Address class)
>     def to_s
>         @fname + " " + @lname + "\n" + "\n" + address.to_s
>     end
> 
> end
> [/CODE]
> 
> [CODE]
> class AddressBook
> 
>     # class variable. keeps track of number of address book entries
>     @@instances = 0

FYI, you don't need this.  The @persons array knows how many entries it
has automatically.  Just call @persons.size when you want to know how
many entries there are. :-)

You should usually avoid class variables in Ruby in my experience in any
case.  There are times they can make sense, but what would happen here
if you had more than a single instance of AddressBook in your program?

>     # no attr_accessor
>     # don't want the user to have direct access to @persons
>     def initialize
>         @persons = [] # starts with empty array
>     end
> 
>     # add person to address book
>     def add(person)
>         @persons += [person]
>         @@instances += 1
>     end
> 
>     # delete person from address book
>     def remove(person)
>         @persons.delete(person)
>         @@instances -= 1
>     end
>      #  totally lost on this part
>     # print sorted by last name method using person's get_lname method
>     def print_addresses
>       @persons.each { |p| persons[p].get_lname.sort  }
>       end # close while loop
>       # print sorted array
>       @persons.each { |p| yield p }
>     end
> 
> end
> [/CODE]

You need to call the sort method on the @persons array rather than the
string you get from Person#get_lname.  There is good documentation for
Array#sort and for the closely related sort_by method mixed in from the
Enumerable module:

http://rdoc.info/docs/ruby-core/1.9.2/Array#sort-instance_method
http://rdoc.info/docs/ruby-core/1.9.2/Enumerable#sort_by-instance_method

For cases such as learning details of sorting, I have usually found it
much better to make a quick script or irb session that pointedly tries
to do what I want to do.  In this case, I would create a very basic
array of strings first and figure out how to sort that.  Then I would
apply it to your larger program.

-Jeremy