Hashes #6

#0 | #1 | #2 | #3 | #4 | #5 | #6 | #7

In our previous page on hashes, we set up a hash of hashes, using my music collection as a source of some interesting data. We set up a simple structure to record artist name, CD title, and track information.

It would be useful to set up some extra fields for genre, and track times. In case you've been too busy to attempt that, I've gone ahead and done it for you. (You're welcome!)

The structure of the record is essentially the same with the addition of these 2 extra fields. But some thought had to go into it.

Here is the new structure to accommodate genre and track lengths:

Since 'genre' is only needed once per artist, we only need to add it under that 'level' of our record. And we only need one entry per artist - their CDs follow underneath.

But 'track time' is needed for each track, so that needs to be at the same 'level' as 'track #' and 'track name'.

An artist typically has more than 1 CD, so we need to close off each CD within 'artist', then close 'artist' at the right point.

It's important to keep all CDs by an artist together under that artist.

Here's what we have with 3 CDs by 2 artists:

In case you're wondering about the format of the track times, I use an excellent program called exiftool to grab ID data from my music files. That is how it is formatted (h:mm:ss).

And the code:

#! /usr/bin/perl
use strict;
use warnings;
BEGIN
{
	open (STDERR,">> $0.txt");
	print STDERR "\n", scalar localtime, "\n";
}
my ($artist,$cd,$tracknum,$track,$genre,$length,%music);
my $Andx=1; #artist index
my $Cndx=1; #CD index
############################### adding track lengths
%music = (
"artists" => {
    "Aural Float"   =>  {
        "genre" =>  "Ambient/Lounge",
        "cds"   =>  {
            "Beautiful Someday"   => {
                "01"  =>  {
                    "title"     =>  "How Deep",
                    "length"    =>  "0:05:25",
                },
                "02"  =>  {
                    "title"     =>  "Dreamer's Dream",
                    "length"    =>  "0:08:45",
                },
                "03"  =>  {
                    "title"     =>  "Him & Her",
                    "length"    =>  "0:05:40",
                },
                "04"  =>  {
                    "title"     =>  "Interlude I",
                    "length"    =>  "0:01:32",
                },
                "05"  =>  {
                    "title"     =>  "Beautiful Someday",
                    "length"    =>  "0:05:29",
                },
                "06"  =>  {
                    "title"     =>  "Gone Forever",
                    "length"    =>  "0:06:27",
                },
                "07"  =>  {
                    "title"     =>  "Still Here",
                    "length"    =>  "0:06:33",
                },
                "08"  =>  {
                    "title"     =>  "Simplicity",
                    "length"    =>  "0:06:29",
                },
                "09"  =>  {
                    "title"     =>  "Interlude II",
                    "length"    =>  "0:01:26",
                },
                "10"  =>  {
                    "title"     =>  "I Adore You",
                    "length"    =>  "0:04:34",
                },
                "11"  =>  {
                    "title"     =>  "Männerwirtschaft",
                    "length"    =>  "0:04:48",
                },
                "12"  =>  {
                    "title"     =>  "Be As You Are",
                    "length"    =>  "0:03:35",
                },
                "13"  =>  {
                    "title"     =>  "Interlude III",
                    "length"    =>  "0:01:07",
                },
                "14"  =>  {
                    "title"     =>  "Life In Dub",
                    "length"    =>  "0:06:23",
                }, # this track
            }, # this cd
        }, # cds
    }, # this artist
    "Acoustic Alchemy"  =>  {
        "genre" =>  "Jazz",
        "cds"   =>  {
            "AArt"  =>  {
                "01" => {
                    "title"     =>  "Wish You Were Near",
                    "length"    =>  "0:04:05",
                },
                "02" =>  {
                    "title"     =>  "AArt Attack",
                    "length"    =>  "0:04:01",
                },
                "03" => {
                    "title"     =>  "Flamoco Loco",
                    "length"    =>  "0:04:05",
                },
                "04" => {
                    "title"     =>  "Tuff Puzzle",
                    "length"    =>  "0:05:14",
                },
                "05" => {
                    "title"     =>  "Passion Play",
                    "length"    =>  "0:04:46",
                },
                "06" => {
                    "title"     =>  "Senjo Wine",
                    "length"    =>  "0:04:33",
                },
                "07" => {
                    "title"     =>  "Viva Ché",
                    "length"    =>  "0:03:44",
                },
                "08" => {
                    "title"     =>  "The Velvet Swing",
                    "length"    =>  "0:05:36",
                },
                "09" => {
                    "title"     =>  "Robbie's Revenge",
                    "length"    =>  "0:04:10",
                },
                "10" => {
                    "title"     =>  "Love at a Distance",
                    "length"    =>  " 0:04:14",
                },
                "11" => {
                    "title"     =>  "Code Name Pandora",
                    "length"    =>  "0:05:10",
                },
                "12" => {
                    "title"     =>  "Nathan Road",
                    "length"    =>  "0:05:07",
                },
                "13" => {
                    "title"     =>  "Cactus Blue",
                    "length"    =>  "0:04:56",
                },
                "14" => {
                    "title"     =>  "The Wind of Change",
                    "length"    =>  "0:02:34",
                }, # this track
            }, # this cd
            "Back on the Case" => {
                "01"    =>  {
                    "title"     =>  "The Alchemist",
                    "length"    =>  "0:03:55",
                },
                "02"    =>  {
                    "title"     =>  "Jamaica Heartbeat",
                    "length"    =>  "0:05:33",
                },
                "03"    =>  {
                    "title"     =>  "Georgia Peach",
                    "length"    =>  "0:04:24",
                },
                "04"    =>  {
                    "title"     =>  "Playing for Time",
                    "length"    =>  "0:06:04",
                },
                "05"    =>  {
                    "title"     =>  "When the Lights Go Out",
                    "length"    =>  "0:04:37",
                },
                "06"    =>  {
                    "title"     =>  "Clear Air for Miles",
                    "length"    =>  "0:06:36",
                },
                "07"    =>  {
                    "title"     =>  "Fire of the Heart",
                    "length"    =>  "0:04:08",
                },
                "08"    =>  {
                    "title"     =>  "Freeze Frame",
                    "length"    =>  "0:04:03",
                },
                "09"    =>  {
                    "title"     =>  "On the Case",
                    "length"    =>  "0:04:00",
                },
                "10"    =>  {
                    "title"     =>  "Break for the Border",
                    "length"    =>  "0:04:54",
                },
            }, # this cd
        }, # cds
    }, # this artist
}, # artists
); # music
#
########################## the magick ######################
#
foreach $artist (sort keys ($music{artists})) {
    print "$Andx $artist ";
    print "[" . ${music}{artists}{$artist}{"genre"} . "]\n";
    $Andx++;
    foreach $cd (sort keys %{$music{artists}{$artist}{cds}}){
        print "\t$Cndx $cd\n"; 
        $Cndx++;
        foreach $tracknum (sort keys %{$music{artists}{$artist}{cds}{$cd} }) {
            print "\t\t [$tracknum] $music{artists}{$artist}{cds}{$cd}{$tracknum}{title} ";
            $length=$music{artists}{$artist}{cds}{$cd}{$tracknum}{length};
            print "($length)\n";
        } # end $tracknum
    } # end $cd
    $Cndx=1;
} # end $artist

Wow, that's quite of bit of data entry. I hope you didn't hand-code all that! Use copy-paste.

There are some odd syntax things in there:

Why the difference: %{$music{artists}{$artist}{cds}} and ${music}{artists}{$artist}{"genre"}

Those aren't typos (this is the actual working script). But how we refer to the hash and its elements depends on the context - do we want a scalar or list returned; and are we printing it, or using it in a loop?

At this point, if your music collection is anything like mine (several gigabytes) you would be forever entering the data into your script

Plus your script would be huge, since it contains all the data necessary to run.

There are some options you could look at now: build a database or put the data into an external file. Then have a Perl script read the file and mangle (manage) it.

Depending on your particular situation (time, size of your collection, and willingness to learn), you could go either way.

In another set of pages I will go over how to put this kind of data into a file and read it back.

Once you have the data you can do whatever you like with it - most of my 'collections' are in a database.