Front page | perl.beginners | Postings from February 2002

## RE: Hash Question

From:
Chas Owens
Date:
February 2, 2002 09:43
Subject:
RE: Hash Question
Message ID:
1012671827.15605.1309.camel@tert.icallinc.com
```Okay, I came up with two solutions.  The first is to use eval to build
the hash and recursive functions to deal with it.  The second takes up
more space, but is easier to deal with: cat the keys together.  The
first is better when you have many things that are going to be the same
and the key size is large.

<data name="test.data">
this is a test
this is a test
this is a test
that was a test
oh my a test
oh my a test
oh my a test
I happen five times
I happen five times
I happen five times
I happen five times
I happen five times
I happen six times
I happen six times
I happen six times
I happen six times
I happen six times
I happen six times
</data>

<example name="t.pl">
#!/usr/bin/perl -w

use strict;
use Data::Dumper;

my %eval_hash;
my %cat_hash;

my @keys = (0, 1, 2, 3);

#eval method, ugly
while (<>) {
chomp;
my @fields = split;

#eval method
my \$eval_str = '\$eval_hash';

for my \$i (0..\$#keys) {
\$eval_str .= "{\$fields[\$i]}";
}

\$eval_str .= "++";

eval \$eval_str;

#cat method
my \$key;

for my \$i (0..\$#keys) {
\$key .= "\$fields[\$i]-";
}
chop \$key; #get rid of last '-'

\$cat_hash{\$key}++;
}

print "%eval_hash:\n", Dumper(\%eval_hash);
print_eval_hash("", \%eval_hash);

print "\n\n%key_hash:\n", Dumper(\%cat_hash);;
print "\$_ = \$cat_hash{\$_}\n" foreach (sort keys %cat_hash);

sub print_eval_hash {
my (\$key, \$ref) = @_;

if (ref \$ref eq 'HASH') {
foreach (sort keys %{\$ref}) {
print_eval_hash("\$key-\$_", \$ref->{\$_});
}
} else {
\$key =~ s/-//; #get rid of first -
print "\$key = \$ref\n";
}
}
</example>

<output from="./t.pl test.data">
%eval_hash:
\$VAR1 = {
'this' => {
'is' => {
'a' => {
'test' => '3'
}
}
},
'I' => {
'happen' => {
'five' => {
'times' => '5'
},
'six' => {
'times' => '6'
}
}
},
'that' => {
'was' => {
'a' => {
'test' => '1'
}
}
},
'oh' => {
'my' => {
'a' => {
'test' => '3'
}
}
}
};
I-happen-five-times = 5
I-happen-six-times = 6
oh-my-a-test = 3
that-was-a-test = 1
this-is-a-test = 3

%key_hash:
\$VAR1 = {
'I-happen-six-times' => '6',
'oh-my-a-test' => '3',
'this-is-a-test' => '3',
'I-happen-five-times' => '5',
'that-was-a-test' => '1'
};
I-happen-five-times = 5
I-happen-six-times = 6
oh-my-a-test = 3
that-was-a-test = 1
this-is-a-test = 3
</output>

On Fri, 2002-02-01 at 15:58, Balint, Jess wrote:
> The way I have the argument parsing set up is for ( 0..\$#ARGV ) { . . .
> When a -f n is presented on the command line, n will be the field number for
> the first hash.
> So if I use -f 1 -f 2 -f 3, there will be three levels of hashes. The top
> level will contain all unique values in the first field of the file. The
> second level will contain all unique values unique to the top level, and the
> third level will be unique to the first and second level. The value of the
> third level key will be a count of the occurance of all the values together
> in the same line.
>
> -----Original Message-----
>
> On Fri, 2002-02-01 at 15:23, Balint, Jess wrote:
> > A scalar value based on the number of command line arguments put into an
> > array.
> >
> >         if( \$ARGV[\$_] =~ /^-f/ ) {
> >         # PARSE TABULATION VALUES
> >                 if( \$table ) {
> >                         \$table =  \$ARGV[\$_];
> >                         \$table =~ s/-f//;
> >                         \$table =  \$ARGV[\$_+1] if( length( \$table ) == 0 );
> >                         \$tables[\$tblcnt] = \$table;
> >                         \$tblcnt++;
> >                 } else {
> >                         \$table =  \$ARGV[\$_];
> >                         \$table =~ s/-f//;
> >                         \$table =  \$ARGV[\$_+1] if( length( \$table ) == 0 );
> >                         \$tables[0] = \$table;
> >                         \$tblcnt++;
> >                 }
> >
> <snip />
>
> First off, you don't need \$tblcnt.  @tables in a scalar context will
> return the number of elements and you can simply push the value onto the
> array (see perldoc -f push).  This also gets rid of the if \$table
>
> Second off, I assume that you are trying to treat -f table and -ftable
> the same.  In which case shouldn't you increment \$_ if you grab the next
> arg?
>
> if ( \$ARGV[\$_] =~ /^-f(.*)/ ) {
> # PARSE TABULATION VALUES
> 	if (defined(\$1)) {             #if there was something after -f
> 		push @tables, \$1;
> 	} else {                       #otherwise use next arg
> 		\$_++;
> 		push @tables, \$ARGV[\$_];
> 	}
> }
>
> print "There were ", scalar(@tables), "tables on the cmdline.\n";
>
>
> Thirdly, where are the keys for the hashes going to come from?  And how
> are you going to know at which level in the hash you want to store the
> data?
>
> To clarify:
> In my example I read the keys from the first three words of a line where
> the first word was the first key, the second word was the second key,
> and the third word was the the third key and then treated the fourth
> word as the data.
>
> --
> Today is Boomtime the 32nd day of Chaos in the YOLD 3168
> Hail Eris!
>