bman has asked for the wisdom of the Perl Monks concerning the following question:
O.K. I'm going out on a limb here. I am VERY fresh to PERL so I still try to get all the concepts right in my head. I took upon myself a task of creating a "simple" PERL script that would generate for me a list of artists, their albums and songs.
So far, I have come up with this script:
while ($line = <ALBUMS>) {
($myArtist, $myAlbum, $mySong, $myLocation) = split('\|', $line);
$mySongs{$myLocation} .= $mySong . "+";
}
foreach $myLocation (sort keys %mySongs) {
++$i;
@mySongs = split('\+', $mySongs{$myLocation});
foreach $mySong (@mySongs) {
print "$mySong\n";
}
}
That onlyl gives me a list of songs and in this case, I would not have to even use hash (let's call it a mental excersise). What I want to do is this:
Artist:
Album:
Songs:
1.
2.
Album2:
Songs:
1.
2.
Artis2:
and so on. In essence I want a grouped report. How can I "attact" this issue (a sample code would be greatly appreciated)?
Thanks.
Re: Hashes hunt me even when I sleep....
by le (Friar) on Oct 05, 2000 at 23:55 UTC
|
my %songs;
while (<DATA>) {
my ($myArtist, $myAlbum, $mySong, $myLocation) = split /\|/;
$songs{$myArtist}->{$myAlbum}->{$mySong} = $myLocation;
}
foreach my $myArtist (sort keys %songs) {
print "$myArtist:\n";
foreach my $myAlbum (sort keys %{ $songs{$myArtist} }) {
print "\t$myAlbum\n";
print "\t\tSongs:\n";
foreach my $mySong (sort keys %{ $songs{$myArtist}->{$myAlbum}
+ }) {
print "\t\t\t$mySong: $songs{$myArtist}->{$myAlbum}->{$myS
+ong}\n";
}
}
}
| [reply] [d/l] |
Re: Hashes hunt me even when I sleep....
by rlk (Pilgrim) on Oct 06, 2000 at 02:14 UTC
|
The code others have posted above is good, so I'll simply
go into a little more depth about what it does.
Once you've got $artist, $album, and
$song for a given line, you're going to want to
put them into a nested hash.
Assume %songs is your "main" hash. What it's
going to contain is references to "anonymous" hashes,
one for each artist, keyed by the name of the artist.
Each of those hashes will contain references to hashes for
each album, keyed by album title. Each album hash will contain,
keyed by the name of the song, some piece of information about
the song, such as it's filename. If you don't want to keep any
information about the song, you can use an array for the innermost
element, instead.
To access an individual element, look it up as
$songs{"artistname"}->{"albumname"}->{"songname"}
#[----]
# %songs is a hash
#[------------------]
# each value in %songs is a reference, to a hash or "hashref".
#[--------------------]
# the "->" dereferences, so we've got a hash to look up
# "albumname" in.
#[---------------------------------]
# the look up in the inner hash returns another hashref
#[-----------------------------------]
# so we dereference again, and we're dealing with another
# hash...
#[----------------------------------------------]
# ...in which we look up "songname", getting whatever.
(The ->'s are optional between '}' and '{', by the way.)
To print the whole thing out again, simply use nested
foreach loops to iterate through
each element.
see perlref for more details, or the second half of
Chapter 4 of the Camel Book
--
Ryan Koppenhaver, Aspiring Perl Hacker
"I ask for so little. Just fear me, love me, do as I say and I will be your slave."
Update:Sorry, I removed the mangled HTML. I had commented something out, and
it took out half the page with it. I feel especially dumb, having done this once already on
E2
| [reply] [d/l] |
(jeffa) Re: Hashes hunt me even when I sleep....
by jeffa (Bishop) on Oct 05, 2000 at 23:48 UTC
|
# warning: untested
my %collection;
while(<ALBUMS>) {
my ($artist, $album, $song) = split;
push @{$collection{$artist}{$album}}, $song;
}
And this will retrieve the data back, unsorted:
foreach my $artist (keys %collection) {
print "$artist:\n";
foreach my $album (keys %{$collection{$artist}}) {
print "\t$album:\n\t\t";
print join("\n\t\t", @{$collection{$artist}{$album}}), "\n";
}
}
Hope this helps,
Jeff
UPDATE: oops, yes isotope - that's what I meant. | [reply] [d/l] [select] |
|
push @{$collection{$artist}{$album}}, $song;
--isotope
http://www.skylab.org/~isotope/
| [reply] [d/l] |
Re: Hashes hunt me even when I sleep....
by kilinrax (Deacon) on Oct 05, 2000 at 23:52 UTC
|
while ($line = <ALBUMS>) {
($artist, $album, $song, $location) = split('\|', $line);
$songlist{$artist}{$album} .= $song . "+";
}
foreach $artist (sort keys %songlist) {
print "Artist: $artist\n";
foreach $album (sort keys %{$songlist{$artist}}) {
print " Album: $album\n";
print " Songs:\n";
$i = 0;
@songs = split('\+', $songlist{$artist}{album});
foreach $song (@songs) {
$i++;
print " $i. $song\n";
}
}
}
(Though this code is untested) | [reply] [d/l] |
RE: Hashes hunt me even when I sleep....
by bman (Sexton) on Oct 06, 2000 at 07:26 UTC
|
To all who posted here: MANY THANKS! from the top of my lungs. Thanks for the tips, code examples and thorugh explanations. There is a saying that "you can bake a cake in many different ways." Oh boy, am I going to get a ride writing in PERL or what? .... :-) | [reply] |
|
Haha..
I think my favorite node here that demonstrates how many
different ways there are to "bake a cake" with PERL is
this one.
| [reply] |
Re: Hashes hunt me even when I sleep....
by bman (Sexton) on Oct 07, 2000 at 06:31 UTC
|
This is my "final" PERL code:
#!/usr/bin/perl -w
$myFile = "/home/mydata/playlist.txt";
print "Content-Type: text/html\n\n";
print "<html><head><title>My Song List</title></head>\n";
print "<body>\n";
open(ALBUMS, "$myFile") or die "Can't open $myFile: $!\n";
while ($line = <ALBUMS>) {
($song, $artist, $album, $location) = split('\|', $line);
$songlist{$artist}->{$album} .= $song . "\+";
$locations{$song} .= $location . "\+";
}
foreach $artist (sort keys %songlist) {
print "<b>Artist:</b> ";
if (!$artist) {
print "\tNot Provided\n";
} else {
print "$artist\n";
}
foreach $album (sort keys %{$songlist{$artist}}) {
print "<blockquote>\n";
print "\t<b>Album:</b>";
if (!$album) {
print "\tNot Provided\n";
} else {
print "\t$album\n";
}
print "<blockquote>\n";
print "\t\t<b>Songs:</b><br>\n";
$i = 0;
@songs = split('\+', $songlist{$artist}{$album});
foreach $song (@songs) {
@thislocation = split('\+', $locations{$song});
foreach $location (@thislocation) {
++$i;
print "\t\t\t$i. <a href=\"http://$location\">$song</a><br>\n";
}
}
print "</blockquote></blockquote>\n";
}
}
Now, mind you that this is just a beginning, something to start on. I'm not sure if anybody else would do this the same way (probably not) but in this case it does a job. I'll throw later some search capabilities and off to fun we go!
P.S. What scares me the most is the fact that I haven't fully realized how I accomplished this task. I was playing with this code until I got it right. It's going to take some time before I feel comfortable with hashes, dereferencing and other "goodies." Meantime, I will enjoy what I have accomplished with you help! :-) | [reply] |
|
|