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

Hello,

I'm reading from a ini-file which lessons and units are available. This information I store in the hash %available_data. The relevant information for me are the keys. The values I set to undef because I'm not interested in.

The following code snippet shows an example how the hash %available_data could look like.

my $unit; my $lesson; $available_data{'02'}{'03'} = undef; $available_data{'02'}{'05'} = undef; $available_data{'02'}{'11'} = undef; $available_data{'05'}{'02'} = undef; $available_data{'05'}{'03'} = undef; $available_data{'07'}{'01'} = undef; $available_data{'07'}{'04'} = undef; $available_data{'07'}{'07'} = undef; $available_data{'07'}{'08'} = undef; foreach $unit (sort keys %available_data) { print "Unit " . $unit . " consists of lessons: "; foreach $lesson (sort keys %{$available_data{$unit}}) { print $lesson . " "; } print "\n"; }
The printed result looks like this:
Unit 02 consists of lessons: 03 05 11 Unit 05 consists of lessons: 02 03 Unit 07 consists of lessons: 01 04 07 08

As you can see I can easily print out which units and lessons are available.

But now I have the following problem: The program is in a specific lesson defined by $unit and $lesson. How do I come to the next lesson.

Examples:
Unit 2, Lesson 11 --> Unit 5, Lesson 2
Unit 5, Lesson 2 --> Unit 5, Lesson 3
Unit 5, Lesson 3 --> Unit 7, Lesson 1

Sorry for this newbie question. But I don't get it.

Thanks for your help

Dirk

Replies are listed 'Best First'.
Re: Navigating in hash of hash
by graff (Chancellor) on Nov 05, 2009 at 08:59 UTC
    Given that you are "sitting at" a particular lesson, do you only need to go to the "next" lesson, or do you also need to be able to go back to the "previous" lesson? You probably need to set up linkages in your hash structure, and it's just a question whether you need the linkage to just go one way, or both ways.

    For the one-way case (link to next), you can set up the linkage by doing a foreach loop in reverse order:

    my $next; # defaults to "undef" for my $unit ( sort { $b cmp $a } keys %available_data ) { for my $lesson ( sort { $b cmp $a } keys %{$available_data{$unit}} + ) { $available_data{$unit}{$lesson} = $next; $next = "$unit $lesson"; } }
    That way, for any specific values of "unit" and "lesson", the hash just stores the values of the "next" unit and lesson, and you just have to split that value on the space character in order to look up that location in the hash. When the value is undef, it means there is no "next" lesson.

    If the hash is supposed to store something else (besides "undef") as the content for each lesson, just add another layer to the hash structure, with "content" and "next" as the keys at that level. (Likewise, if you have to store linkage in both directions, have "next" and "prev" as keys for storing the "unit lesson" values, as well as a "content" key, if needed.)

      Thank you a lot for your ideas. At the end I took the solution of graff. It is working fine. Here my code:
      my $unit; my $lesson; my $next; # defaults to "undef" $available_data{'02'}{'03'} = undef; $available_data{'02'}{'05'} = undef; $available_data{'02'}{'11'} = undef; $available_data{'05'}{'02'} = undef; $available_data{'05'}{'03'} = undef; $available_data{'07'}{'01'} = undef; $available_data{'07'}{'04'} = undef; $available_data{'07'}{'07'} = undef; $available_data{'07'}{'08'} = undef; for $unit ( sort { $b cmp $a } keys %available_data ) { for $lesson ( sort { $b cmp $a } keys %{$available_data{$u +nit}} ) { $available_data{$unit}{$lesson}{'next'} = $next; $next = "$unit-$lesson"; } } # Unit 05, Lesson 03 --> Unit 07, Lesson 01 $unit = "05"; $lesson = "03"; print "Unit " . $unit . ", Lesson " . $lesson . " --> Unit " . substr($available_data{$unit}{$lesson}{'nex +t'}, 0, 2) . ", Lesson " . substr($available_data{$unit}{$lesson}{'next +'}, 3, 2) . "\n";

        perldsc might be helpful in the future too...

        Just a something something...
Re: Navigating in hash of hash
by grizzley (Chaplain) on Nov 05, 2009 at 08:34 UTC

    I am not sure if I understand it correctly, but you can't. I mean I think you want some kind of iterator to move (in a hash) from lesson to lesson in order but there is no such thing. You need to write it by yourself. As you iterate over all elements, store them in an array and then you can iterate over array to get what you need.

    Update: Following structure comes to my mind:
    $available_data{'02'}{'03'} = {unit => '02', lesson => '03', next => u +ndef}; $available_data{'02'}{'05'} = {unit => '02', lesson => '05', next => u +ndef}; $available_data{'02'}{'03'}{next} = $available_data{'02'}{'05'}; $available_data{'02'}{'11'} = {unit => '02', lesson => '11', next => u +ndef}; $available_data{'02'}{'05'}{next} = $available_data{'02'}{'11'}; etc...

    Then next lesson's data for $unit and $lesson would be (untested)

    $ref = $available_data{$unit}{$lesson}; print "Unit: $unit, lesson: $lesson -> Unit: ", $ref->{unit}, ' lesson +: ', $ref->{lesson};

    Update2: but it would be soooo much easier to make it as array from the beginning:

    my @available_data; push @available_data, {unit => '02', lesson => '03'}; push @available_data, {unit => '02', lesson => '05'}; push @available_data, {unit => '02', lesson => '11'}; push @available_data, {unit => '03', lesson => '02'};
Re: Navigating in hash of hash
by Krambambuli (Curate) on Nov 05, 2009 at 08:22 UTC
    What about

    print $lesson . " " . $available_data{$unit}{$lesson} . "\n";

    ?

    Krambambuli
    ---