Hashes #3

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

I find these kinds of data structures are hard to get a handle on, so I decided to use some data that I was familiar with. Here is a very small collection of some of my music collection.

This particular structure is a hash of hashes.

Paste this into a new Perl script:

#! /usr/bin/perl
use strict;
use warnings;

my ($artist,$cd,$tracknum,$track,%music);
my $Andx=1; #artist index
my $Cndx=1; #CD index

%music = (
    "Aural Float"   =>  {
            "Freefloat" => {
                "01" => "Perspectives",
                "02" => "Freefloat",
                "03" => "Switchin' The Wave Of Thought",
                "04" => "Soulsearching",
                "05" => "Travelogue",
                "06" => "At The Crossroads",
                "07" => "New Frontiers",
                "08" => "Zwei G",
                "09" => "Session 5",
                "10" => "AF Study II",
                "11" => "Switchin' The Wave Of Thought (Reprise)",
            },
            "Beautiful Someday"   => {
                "01"  =>  "How Deep",
                "02"  =>  "Dreamer's Dream",
                "03"  =>  "Him & Her",
                "04"  =>  "Interlude I",
                "05"  =>  "Beautiful Someday",
                "06"  =>  "Gone Forever",
                "07"  =>  "Still Here",
                "08"  =>  "Simplicity",
                "09"  =>  "Interlude II",
                "10"  =>  "I Adore You",
                "11"  =>  "Màˆnnerwirtschaft",
                "12"  =>  "Be As You Are",
                "13"  =>  "Interlude III",
                "14"  =>  "Life In Dub",
            },
        },
);

In this example, 'Aural Float' is a key to two values: 'Freefloat' and 'Beautiful Someday'.

They in turn are each keys to a hash of track numbers, which are keys to track names (values).

To print a list (sorted by artist and CD) ...

foreach $artist (sort keys (%music)) {
    print "$Andx $artist\n"; 
    $Andx++;
    foreach $cd (sort keys $music{$artist}) {
        print "\t$Cndx $cd\n"; 
        $Cndx++;
        foreach $tracknum (sort keys $music{$artist}{$cd}) {
            print "\t\t$tracknum $music{$artist}{$cd}{$tracknum}\n";
        }
    }
}

Very nice, we've even added a counter for artist, and their CDs.

But can you search for something?

print "Do you have anything by 'Aural Float'?\n";
if (exists($music{"Aural Float"})) {
    print "Yes I do:\n" ;
    for $cd (sort keys $music{'Aural Float'} ) {
        print "\t $cd\n";
        $cdSaved=$cd;
    }
}

Great ... "What are the tracks on 'Freefloat'?"

$cd = "Freefloat";
print "What are the tracks on '$cd'?\n";
foreach $artist (keys %music) {
        foreach $tracknum (sort keys $music{$artist}{$cd}) {
            print "$tracknum $music{$artist}{$cd}{$tracknum}\n";
        }
}

Finally, can you search for a track by an artist?

This one is a little tricky, because now we need to search for a value not a key. We can't use exists for this, since that only looks for keys.

my $query = "Interlude II"; # comment this line & uncomment next line to try 'unfound'
#my $query = "0asdf09a8dsI"; # uncomment this line & comment previous line to try 'unfound'
$artist = "Aural Float";
my $found;
print "Do you have '$query' by '$artist'?\n";
foreach $cd (keys $music{$artist}) {
    foreach $tracknum (keys $music{$artist}{$cd}) {
        if ($query eq $music{$artist}{$cd}{$tracknum}) {
        # use 'eq' instead of '=~' to match exact track
            $found=1;
            print "Yes, it's on '$cd', track $tracknum\n" if ($found==1); 
        }
        else {
            $found=0;
        }
   }
}
print "Not found.\n" if (! $found); 

We've used variables to hold our search item and artist - they can be used just like a literal string in the search code.

We've also used eq instead of the match operator =~ because there are other tracks that are similar to our query, but only 1 exact match.

I hope with these examples you can begin to see the power of hashes.

Next, what else can we do with hashes?