Re: Dynamic Hash
From: R. Joseph Newton (rjnewton_at_efn.org)
Date: 11/18/03
- Next message: R. Joseph Newton: "Re: pagination of dbi results on html browser"
- Previous message: R. Joseph Newton: "Re: When MUST you use 'map' ?"
- In reply to: Mr. John Kent: "Dynamic Hash"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Mon, 17 Nov 2003 23:30:56 -0800 To: "Kent, Mr. John" <kent.saic@nrlmry.navy.mil>
"Kent, Mr. John" wrote:
> Greetings,
>
> Am using perl to dynamically write some JavaScript code
> that creates cool drop down button menus by Ger Versluis found
> on http://www.dynamicdrive.com ( for those who want to
> know why).
>
> Have a directory structure in which the target files are located
> at various levels of sub-directories.
>
> Trying to create a dynamically sized hash of unknown dimensions
> where each sub directory name is a dimension of the hash and it
> gets assigned the file.
Please read the documentation on hashes before making assumptions about how they look. There are ways to use a string as a
variable name, but that is a very advanced issue. There are almost always better ways to do things
>
>
> For example
> my(%HASH);
> $HASH{$sub1}{$sub2}{$sub3} = $file1;
> $HASH{$sub1}{$sub2}{$sub3}{$sub4}{$sub5} = $file2;
Nope. Hashes cannot be contained inside other structures.
The constructors for both arrays and hashes use lists of scalars. When you put a hash or array directly into another
structure, you "flatten" it tpo a list of scalars, squeezing the magic out of it in the process:
*******************
Greetings! E:\d_drive\ocf\discuss\prototype>perl -w
my %ordianl_hash = (first => 1, second => 2, third => 3);
my @array = (5, 6, %ordianl_hash, 34, 'Jack Sprat');
print "$_, " foreach @array;
print "\b\b \n\n";
print "$array[2]\n";
^Z
5, 6, first, 1, second, 2, third, 3, 34, Jack Sprat
first
******************
If you wish to make progress in the direction of multi-dimensional data structures, you *must* become adept at using
references. Perl provides no alternate means of handling the issue.
> Here is what I tried, unsuccessfully
>
> no strict 'refs'
>
> # @TERMS is an array of each sub-directory name up to the one containing the target file
>
> my(%NAV_HASH);
> # Build the multi-dimensional hash
> my($hash_string) = "NAV_HASH";
> foreach my $sub_dir (@TERMS){
> $hash_string .= "{\"$sub_dir\"}";
> }
> print "hash_string = $hash_string\n" if ($DEBUG == 1); # <- This looks good
> # Producing a hash_string = NAV_HASH{"Africa"}{"focus_regions"}{"OEF_Somalia"}{"Overview"}{"high_low_cloud"}
>
> # Now turn this string into a real hash and
> # assign it a value
> $$hash_string = "$last,";
Strings are data. Hashes and variables are programming structures. Don't try to mix the two.
my $volume_root = {};
$volume_root->{'Program Files'} = {};
$volume_root->('WinBlows'} = {};
$volume_root->{'WinBlows'}->{'System32'} = {};
Actually, here you could skip the second statement, even, since the assignment to a sub-reference auto-vivifies the keys in
between.
Greetings! E:\d_drive\ocf\discuss\prototype>perl -w
my $volume_root = {};
$volume_root->{'WinBlows'}->{'System32'} = {};
$volume_root->{'WinBlows'}->{'System32'}->{'name'} = 'Dirty Tricks';
print "$volume_root->{'WinBlows'}->{'System32'}->{'name'}\n";
^Z
Dirty Tricks
Note that this is all hard-coded, though. The program structures were never strings per-se, in the same sense as data
strings.
A practical [and working] example from my current project:
# In function launch_full_text_search:
my $file_keys = [sort {$a <=> $b} keys %$files]; # %$files => hash pointed to by $files
while (my $file_key = shift @$file_keys) { # @$file_keys => array pointed to by $file_keys
seek_full_text_in_file($regex, $file_key, $files, $found_in)
}
In the called function, seek_full_text_in_file:
sub seek_full_text_in_file {
my ($regex, $file_key, $files, $found_in) = @_;
my $file = $files->{$file_key};
open IN, $file or die "Could not open $file $!";
my $line;
$line = <IN> until $line and $line eq "\x0A";
{
local $/;
$line = <IN>;
$line =~ s/[\012\015]/ /g;
if (my $count = () = $line =~ /$regex/gi) {
$found_in->{$file_key}->{filename} = $file if not $found_in->{$file_key};
$found_in->{$file_key}->{count} += $count;
}
}
}
This does not get as deeply nested as a directory tree, of course, but you should be able to see how references link together
the layers of the structure. Once you get the hang of using references, you can use them to drill down as far into
structures as you want. Note also that the original structures in the calling function are modified by the actions using the
reference. This can be very powerful.
perldoc perlref
perldoc perlreftut
Joseph
- Next message: R. Joseph Newton: "Re: pagination of dbi results on html browser"
- Previous message: R. Joseph Newton: "Re: When MUST you use 'map' ?"
- In reply to: Mr. John Kent: "Dynamic Hash"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]