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

Hi,

I have a file which for every line has the fields (separated by tabs): title, file, offset. What I want to be able to do is given a title get the file and offset. I'm pretty sure it's a job for an array of hashes but after reading some docs about this I still can't figure out how to get the data into the array of hashes and how to extract it after it's there. How would I do this?

Replies are listed 'Best First'.
Re: newbie hash question
by PodMaster (Abbot) on Jul 23, 2003 at 04:00 UTC
Re: newbie hash question
by Enlil (Parson) on Jul 23, 2003 at 03:59 UTC

    I noticed you mention having read "some docs", but take a look at perldsc (particularly the section the link points to on the Declaration of, and accessing of Arrays of Hashes.), if you haven't already done so. (and there is nothing embarrasing about posting some code so we know what you have already tried.) Also perlreftut should prove helpful as well.

    -enlil

      Thanks Enlil, that was very helpful. Turns out what I was looking for was a hash of hashes. Here's the code I came up with:

      #! c:\perl\bin use strict; use warnings; my @temp=(); my %HoH=(); while(<>){ (/^Title/) and next; chomp; @temp=split/\t/; $HoH{$temp[0]}{file}=$temp[1]; $HoH{$temp[0]}{offset}=$temp[2]; }

      -----------------------------------

      Any comments about coding style are welcome.
Re: newbie hash question
by NetWallah (Canon) on Jul 23, 2003 at 06:02 UTC
    Bravo (++ vote) dannoura on getting the HoH right!

    Since you invited comments, I would replace the @temp array with scalars, and use them thus:

    my ($title,$file,$offset) =split/\t/; $HoH{$title}{file}=$file; $HoH{$title}{offset}=$offset;
    That makes the code a whole lot easier to read and marginally, more efficient.

    To improve it marginally (although, newbies may find this more confusing), the exact equivalent code is:

    my ($title,$file,$offset) =split/\t/; $HoH{$title}={file=>$file, offset=>$offset};
Re: newbie hash question
by Cody Pendant (Prior) on Jul 23, 2003 at 06:44 UTC
    I don't see why you need a data structure at all if you're just saying "I want to search the file with a title and have it tell me the file and offset".

    Just read the file and grab and process the line only if it matches the title:

    while(<FILE>){ if(/^$title/){ (undef,$file,$offset) = split('\t'); last; } }

    I mean, you only need the HoH or HoA or whatever if you want to keep the file in memory and do stuff more than once, right? Or am I missing something?



    ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print

      Yes, but I'm doing it 6,000 times so I thought it would be more efficient to have a hash lookup instead of looping through the file 6,000 times.

      -----------------------------------

      Any comments about coding style are welcome.
        Aha, that certainly comes under the heading of "am I missing something", yes. Of course it's better that way. Mind you even better (going completely the other way) would be to dump it into a simple tied-hash database of some kind. That way you'd have it on disk for later if you wanted to do other things to it. I'd just use dbm if it was me.

        ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss') =~y~b-v~a-z~s; print
Re: newbie hash question
by bobn (Chaplain) on Jul 23, 2003 at 04:02 UTC

    Un-Tested

    open(IN, "<file") or die "failed: $!"; while(<IN>) { chomp; my ($title, $file, $offset ) = split(/\t/, $_); $offsets{$title} = $offset; $files{$title} = $file; }

    2 separate hashes. This is assuming that $title is unique.

    To use:

    $title = 'somethng interesting'; $offset = $offsets{$title}; $file = $files{$title};
    --Bob Niederman, http://bob-n.com