> -----Original Message----- > From: matz / netlab.co.jp [mailto:matz / netlab.co.jp] > Sent: den 16 juni 2000 10:00 > To: ruby-talk / netlab.co.jp > Subject: [ruby-talk:03458] Re: Array of structs in Ruby > > > Hi, > > In message "[ruby-talk:03452] Re: Array of structs in Ruby" > on 00/06/16, Jilani Khaldi <jilanik / tin.it> writes: > Jilani and Matz: |#include <stdio.h> |struct person { class Person | char name[32]; attr_accessor :name |}; end |struct person p[2]; persons = [Person::new, Person::new] |int i; |main() |{ |for (i = 0; i < 2; i++) for p in persons |{ | printf("\nName: "); | scanf("%s", p[i].name); p.name = readline() |} end |printf("\n\n----------"); printf("\n\n----------") |for (i = 0; i < 2; i++) for p in persons |{ | printf("\nName: %s", p[i].name); printf "\nName: %s", p.name | printf("\n"); printf "\n" | } end |return 0; |} While Matz's answer is quite good one to one translation of the original problem to Ruby, I'd like to highlight few points: __There's no magic numbers__: The Ruby version hasn't magic numbers (or should have only one). Additionally it's much safer than the C equivalent. The Ruby version can't fail even if the name read is longer than 32 characters. OTOH, if 32 chars was part of the requirement, the Ruby code like the C doesn't do anything to ensure the the constraint is honored. Matz is taking a shortcut when for(i=0;i<2;i++) is replaced with for p in persons, and that's good because the knowledge of the amount of entries is abstracted away (again this applies only unless the intention was to read and print just two, no matter how many we have allocated.) Jilani: > |> persons = [Person::new, Person::new] > | > |but if I need here, say, 1000 records, or better, a variable > |number of records, how to declare them? Matz: > persons = [] > 1000.times{ persons.push(Person::new) } > or > persons = (0...1000).collect{ Person::new } __There's (normally) no need for preliminary allocations__: Ruby is a dynamic language so many times there's no need for "statically made allocations". Striving to get around without them is good. In C the information of the size of the array is used three times, while it's necessary only once (thus Matz changed the code to use 'for p in persons' instead of hardcoding the size like 'for i in (0...2); print persons[i];' But now to your question. If you need, say 1000 records, you shouldn't declare them unless you want your code to express there's really 1000 records. (Or for performance.) So instead of saying persons = [Person::new, Person::new] for p in persons p.name = readline() end and declaring your array (fully) you should say persons = [] # state it's an array (as_many_times_as_I_happen_to_like_to).times do persons.push( Person.new( readline() ) ) end With time if you happen to like something else, you don't have to change this part of the code at all (note: as_many_..._like_to could be a variable as well as a function call :). Now a point about the performance. If you're sure you will be populating an array of 1 000 000 million items you could (and should) preallocate it by saying persons = Array.new( size_of_the_array ). The reason for this is that first the array is as small as possible and with every array.push it's reallocated for the new larger size, thus unnecessarily spending time just reallocating. Anyway, the bottom line is: it's time to start thinking dynamically! When you want to do something with the persons in an array, you should say something like 'for p in persons' instead of declaring the index iterator, defining a loop from zero to the size of the array, and accessing the element. Sometimes you want to work with those indexes and then you want to make a index variable. - Aleksi