Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: Stuck while learning about the hash

by Arguile (Hermit)
on Jun 08, 2001 at 11:40 UTC ( [id://86858]=note: print w/replies, xml ) Need Help??


in reply to Stuck while learning about the hash

Hrmm... I might be really off here but wouldn't this construct be simpler? (pretty new to perl as well and not fully conversant with the intricacies of hashes)

#!/usr/bin/perl -w use strict; my %data; open DB, "db.txt"; while (<DB>) { @_ = split/[\t,|\n]/; $data{ $_[0] } = { @_[1..$#_] }; } close DB;

I tried shift @_ then just @_ in the right side of the equation and learned again that it's evaluated all as one not left to right ;). Anyways, this way you get a data structure something like this:

# pseudo representation 615 = ( MNH => 36.00 USED => 12.00 PB => 50.00 )

Some examples on how to access it.

keys %data # 614, 615, 616 $data{615} # an anon hashref $data{615}{USED} # 12.00 keys %{ $data{615} } # MNH, USED, PB

Printing out the structure (I've never used DATA::Dumper might it apply here?):

for my $key (keys %data) { print "\n$key"; my $h_ref = $data{$key}; printf "\t%s\t%6.2f\n", $_, $h_ref->{$_} for keys %$h_ref; }
tilly suggested the $h_ref for speed (less hash lookups per inner loop iteration), I'm declaring inside because I'm lazy and don't want to undef it after.

It's output:

614 MNH 16.00 USED 32.00 PB 50.00 615 MNH 36.00 USED 12.00 PB 50.00 616 MNH 96.00 USED 2.00 PB 10.00

I didn't do any of the null checks, but that's pretty trivial to add. The \n in the split handles getting rid of the newline.. chomp may be better, I'm not sure.

Update

Just for fun I one lined the db to hash (not exactly efficient):

$data{ (split/\t/)[0] } = { (split/[\t,|\n]/)[1..6] } while <DB>;
Update 2

Oops, fixed up what Hofmator suggested... I swear I knew that about char classes I just didn't know split well enough and it sort of evolved that way as I worked through ;). Thanks.

Replies are listed 'Best First'.
Re: Re: Stuck while learning about the hash
by Hofmator (Curate) on Jun 08, 2001 at 12:46 UTC

    I just want to point out a small error in your code, which in this case proved to be no error at all - but just because you were lucky. You wrote:

    while (<DB>) { @_ = split/[\t|,|\||\n]/; # here things go accidently righ +t ;-) $data{ $_[0] } = { @_[1..$#_] }; }

    You wanted to split on  <tab>, <,>, <|> or <newline> and you used a character class for that. A character class matches any of the characters in that class, e.g. [aeiou] matches any one vocal and you must not use an alternation character <|> in the class! The code worked nevertheless as - by chance - the <|> is part of the character class. It need not be escaped, but you can do it if you want. If you want to use alternation than you would have to write

    @_ = split /\t|,|\|\n/;
    but this is not efficient. The character class is the better idea. So you would end up with
    @_ = split /[\t\n,|]/;

    Furthermore, if you are not sure whether there is additional space around the delimiters this would change to

    @_ = split /[\s,|]+/;

    allowing for one or more of the chars in the character class. I also removed the split on the ending <newline> as this only produces an empty field at the end which is not returned by split.

    See also split and perlre.

    -- Hofmator

      Here's my 10-ct's worth. This is a bit after all the other posts, so it's probably not much help, (insert random excuse here about having to work next to my client) but I decided to post it anyways.

      I got lazy and I also noticed that this is a question about learning to use hashes so I'm keeping the hash references down to a minimum and am using the key to point to useful data. However, doing this loses the sorting capabiltiy that a hash of hashes would allow, so it's sub-optimal.

      #!/usr/bin/perl -w use strict; my %items; open(DB, "db.txt") || die "Could not open the database: $!"; while(<DB>) { chomp; my @record = split(/\t/); my $scottnum = shift @record; my @details = split(/\|/, shift @record); foreach my $detail (@details) { my @item = split(/,/, $detail); if ( ($item[0]) && ($item[1]) ){ $items{$scottnum.'-'.(shift @item)} = shift @item; } } } foreach my $key (sort (keys %items) ) { my ($sn,$mk) = split ('-',$key); print "key: $key \tmk: $mk\t sn: $sn item: $items{$key}\n"; }

      The script returns:

      key: 614-16.00 mk: 16.00 sn: 614 item: MNH key: 614-32.00 mk: 32.00 sn: 614 item: USED key: 614-50.00 mk: 50.00 sn: 614 item: PB key: 615-12.00 mk: 12.00 sn: 615 item: USED key: 615-36.00 mk: 36.00 sn: 615 item: MNH key: 615-50.00 mk: 50.00 sn: 615 item: PB key: 616-10.00 mk: 10.00 sn: 616 item: PB key: 616-2.00 mk: 2.00 sn: 616 item: USED key: 616-96.00 mk: 96.00 sn: 616 item: MNH

      tested on solaris something or other.

      I noticed in the original code that the printing statement was in the wrong place, which is most of why the output errors happened.

      --hackmare.

Re: Re: Stuck while learning about the hash
by Stamp_Guy (Monk) on Jun 09, 2001 at 07:11 UTC
    This looks like what I was trying to do, but here are a couple problems:

    1. I want to be able to keep the items in order.
    2. I'm dealing with a relatively large file (10,000+ lines), thus it takes an eternity to load everything into memory.
    3. Sometimes I won't know what will be in the place where I inserted USED, MNH, and PB.

    I was working on this project to learn more about hashes and all of you guy's code helped me out tremendously in learning how to use them. I've still got a lot to learn, but you've helped give me a good start.

    Question: is there a way I could make a script like this that would be portable, yet much quicker?

    Stamp_Guy

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://86858]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (9)
As of 2024-04-19 06:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found