atu has asked for the wisdom of the Perl Monks concerning the following question:

Hi all;

I have a problem described on the title, need a structure array within structure array.

Now what i have come up yet is:

my @classrooms; my %classroom = ( classroomID =>'$', classroomName=>'$', students=> \%student, ); my %student = ( studentName => '$', studentSurname=> '$', studentID=> '$', age=> '$', );

now lets say there are 3 classrooms, named classroom1,classroom2,classroom3 as well as classroomIDs 10,11,12. now each classroom has different number of students, but i guess it wont be a problem since we dont use array sizes in perl. and naturally each student have a name, surname,id and age.

I want to store that data in that classrooms array... but how do I make that happen!

my $student = ( studentName => 'John', studentSurname=>'Something' +, studentID=>'9534', age=>'12' ); my $student = ( studentName => 'Mary' ,studentSurname=>'Something2 +', studentID=>'5489', age=>'13' ); my %classroom = (classroomID => 10, classroomName=>'classroom1');

Students are created without a problem I think but I didn't push them into any of the classroom arrays. And that classroom structure is not even generated i guess since I didnt even create anything for student variable,

How do I generate a classroom data and push those students into classroom1? And how can i access them?

$classrooms[0]->students[0]->studentName
will probably not work. Can anyone help with this?

Replies are listed 'Best First'.
Re: Array of structures within an array of structures.
by kcott (Archbishop) on Sep 20, 2013 at 13:24 UTC

    G'day atu,

    Welcome to the monastery.

    You have some syntax errors there (e.g. my $student = (...); my $student = (...);). Use the strict and warnings pragmata to get feedback from Perl: see my code below for usage.

    I'm guessing you're probably after something like this:

    #!/usr/bin/env perl -l use strict; use warnings; use Data::Dumper; my @classrooms; my @students = ( { studentName => 'John', studentSurname => 'Something', studentID => 9534, age => 12 }, { studentName => 'Mary', studentSurname => 'Something2', studentID => 5489, age => 13 }, ); my %classroom = ( classroomID => 10, classroomName => 'classroom1' ); push @{$classroom{students}}, @students; push @classrooms, \%classroom; print 'Name of 1st student in 1st classroom: ', $classrooms[0]{students}[0]{studentName}; print 'The whole school:'; print Dumper \@classrooms;

    Output:

    Name of 1st student in 1st classroom: John The whole school: $VAR1 = [ { 'classroomName' => 'classroom1', 'students' => [ { 'studentSurname' => 'Something', 'studentID' => 9534, 'studentName' => 'John', 'age' => 12 }, { 'studentSurname' => 'Something2', 'studentID' => 5489, 'age' => 13, 'studentName' => 'Mary' } ], 'classroomID' => 10 } ];

    I'd recommend you look at "perldsc - Perl Data Structures Cookbook" which describes these types of structures in detail.

    -- Ken

Re: Array of structures within an array of structures.
by toolic (Bishop) on Sep 20, 2013 at 12:51 UTC
Re: Array of structures within an array of structures.
by Laurent_R (Canon) on Sep 20, 2013 at 13:10 UTC

    So, if I get you right, you want to have an array of classrooms, each classroom being a hash containing some information on the classroom and an array of students, each student being in turn a hash.

    There are many ways to construct this structure, and the best way may vary depending on where your data is coming from. You might find it easier to start from the bottom (lower level structures) and make your way up.

    You could start by creating a student list with something like this:

    my @student_list; push @student_list, { studentName => 'John', studentSurname=>'Somethin +g', studentID=>'9534', age=>'12' }; push @student_list, { studentName => 'Mary' ,studentSurname=>'Somethin +g2', studentID=>'5489', age=>'13' };

    The @student_list array is now an array of anonymous hash refs (references to student hashes). Next, you want to create a classroom hash, which could be done as follows:

    my %classroom = (classroomID => 10, classroomName=>'classroom1', students => \@student_list);

    The structure now looks like this:

    0 HASH(0x80355e98) 'classroomID' => 10 'classroomName' => 'classroom1' 'students' => ARRAY(0x80359e18) 0 HASH(0x8006c050) 'age' => 12 'studentID' => 9534 'studentName' => 'John' 'studentSurname' => 'Something' 1 HASH(0x8032f958) 'age' => 13 'studentID' => 5489 'studentName' => 'Mary' 'studentSurname' => 'Something2'

    The final step is to push a a ref to %classroom onto an array of classrooms:

    push @classrooms, \%classroom;

    To access the surname of the second student, one possible way:

    print $classrooms[0]{students}[1]{'studentSurname'}; # prints 'Someth +ing2'

    Or, if you prefer:

    print $classrooms[0]->{students}->[1]->{'studentSurname'}; # prints 'Something2'
Re: Array of structures within an array of structures.
by VinsWorldcom (Prior) on Sep 20, 2013 at 13:14 UTC

    Something like this:

    UPDATE: In my zest to copy the original code, I made a mistake in my code below. Thanks Laurent_R for pointing it out in the node below. Corrected code follows:

    # your initial definitions here # maybe a loop starts here my $student; # single student my @students; # all students in 1 class $student = { studentName => 'John', studentSurname=>'Something', studentID=>'9534', age=>'12' }; push @students, $student; # Eliminate loading next student below explicitly # by using a loop to read from source file, DB, etc. $student = { studentName => 'Mary', studentSurname=>'Something2', studentID=>'5489', age=>'13' }; push @students, $student; %classroom = ( classroomID => 10, classroomName => 'classroom1', students => \@students ); # Rinse, repeat

      Hi VinsWorldcom,

      I guess it's a typo, but this part in your code:

      $student = ( studentName => 'John', studentSurname=>'Something', studentID=>'9534', age=>'12' ); push @students, $student;

      probably does not work properly, as far as I can say. The value of $student is now 12 because you are assigning a list to a scalar, and you're then pushing 12 into @students.

      You probably want either directly an hash ref like this:
      $student = { studentName => 'John', studentSurname=>'Something', studentID=>'9534', age=>'12' }; push @students, $student;

      Or an hash on which you later take a ref:

      %student = ( studentName => 'John', studentSurname=>'Something', studentID=>'9534', age=>'12' ); push @students, \%student;

      You're right, I'm wrong. I've corrected my code in the node above (so as to not leave incorrect code there for posterity) and provided credit to you so your above correction doesn't seem misplaced.

      Thanks!

Re: Array of structures within an array of structures.
by aaron_baugher (Curate) on Sep 20, 2013 at 14:21 UTC

    One suggestion I would have is that, if your classrooms and students have unique IDs, you put them in a hash with that ID as the key, rather than an array. That will make accessing the data by those IDs simpler. Here's an example of creating such a structure, accessing its values in a couple of different ways, and adding to it:

    #!/usr/bin/env perl use strict; use warnings; my %classroom = ( 10 => { classroomName => 'classroom1', student => { 9534 => { studentName => 'John', studentSurname => 'Doe', age => '12', } }, }, ); my $room = 10; my $kid = 9534; print <<END; Student $kid in room $classroom{$room}{classroomName} is $classroom{$room}{student}{$kid}{studentName} $classroom{$room}{studen +t}{$kid}{studentSurname}, who is age $classroom{$room}{student}{$kid}{age}. END # Add a classroom $classroom{11} = { classroomName => 'classroom2', }; # Add a student to new classroom $classroom{11}{student}{5489} = { studentName => 'Mary', studentSurname => 'Smith', age => 13, }; # Add a student to old classroom $classroom{10}{student}{3456} = { studentName => 'Jim', studentSurname => 'Baker', age => 14, }; # Print structure print "Students listed by classroom\n"; for my $cid (keys %classroom) { print "Classroom ID $cid, name $classroom{$cid}{classroomName}\n"; for my $sid (keys %{$classroom{$cid}{student}}) { my $student = $classroom{$cid}{student}{$sid}; #for less typin +g print ' ', join ' ', $sid, @{$student}{qw/studentName studentSurname age/}; print "\n"; } } # Print raw structure use Data::Dumper; print "\n\n", Dumper %classroom;

    Aaron B.
    Available for small or large Perl jobs; see my home node.

Re: Array of structures within an array of structures.
by Anonymous Monk on Sep 20, 2013 at 13:26 UTC
      corerection
      my @classrooms = ( { classname => 1, students => [ { age => 0, fn => 0, id => 0, ln => 0 }, { age => 1, fn => 1, id => 1, ln => 1 }, ], }, ) ; my @classrooms; $classrooms[0]{students}[0]{ln} = 0; #d3 $classrooms[0]{students}[0]{id} = 0; #d3 $classrooms[0]{students}[0]{age} = 0; #d3 $classrooms[0]{students}[0]{fn} = 0; #d3 $classrooms[0]{students}[1]{ln} = 1; #d3 $classrooms[0]{students}[1]{id} = 1; #d3 $classrooms[0]{students}[1]{age} = 1; #d3 $classrooms[0]{students}[1]{fn} = 1; #d3 $classrooms[0]{classname} = 1; #d1
Re: Array of structures within an array of structures.
by Anonymous Monk on Sep 20, 2013 at 13:58 UTC
    Also, be sure that you conceptually understand what the finished data structure will look like. Every "element of" an array, hash, or list is "a single element," but that "single element" can be a reference to anything-at-all ... which, in turn, can have more-than-one reference to it at a time. Perl's syntax is especially generous in this regard, to make it very easy to manipulate these structures and for Perl to "do the right thing." Carefully read over the perldoc's about "references" and about its approach to memory management. Until you have a crystal-clear mental picture of that, you're going to continue to feel very confused ... especially if you are used to working with other languages that support "strong typing."
Re: Array of structures within an array of structures.
by marinersk (Priest) on Sep 20, 2013 at 16:47 UTC
    Hello atu,

    A quick summary of all the wonderfully complete advice you have thus far received:

    Look into Hash of Hashes, Hash of Arrays, Array of Hashes. Often abbreviated HoH, HoA, AoH.

    There will likely be some time needed to absorb -- but well worth the effort.

    My two cents and all that rot.

      Thanks a lot! I will check them asap!
Re: Array of structures within an array of structures.
by Marshall (Canon) on Sep 21, 2013 at 08:38 UTC
    Now lets say there are 3 classrooms: named classroom1, classroom2, classroom3 as well as classroomIDs 10,11,12, These mean the same thing.

    These terms are exactly equivalent.
    Since these terms mean the same, we can “normalize” these terms to be the same text (classroom2 means number 11)

    my $student = ( studentName => 'John', studentSurname=>'Something', studentID=>'9534', age=>'12', Class=>10 );

    It would also be “ok” in an Excel spreadsheet to have: array like this:
    ”John”,”Something”,”9534”,”12”,”10”

    A Perl Array of Hash is close to a C "Array of Struct" or even an Excel "line" when properly spaced although that might not be so apparent to many. There is sure to be some fancy translations between BIO101, Class VV, etc that will/can be done in an SQL database.