array of hashes with a little more...

M

mikeybe

OK. I'm having a bear of a time with this. I think the best way to
present this is to describe the data set and then ask someone to help
me figure out HOW to organize the data.

I am writing a program to pull out data from a pipe delimited file that
has library book information (it's a new book list generated from our
library catalog) like this:

isbn|dewey decimal number|title|author

I know how to read the file and break the elements apart etc. The goal
of the program is to create RSS feeds by dewey number. So, an RSS feed
will have books from 000-100, another 100-200 etc. so people can
subscribe to the new books feed by subject. I am making this list
dynamic so I can alter the list and the program will still work. Like
this:

my @deweystring= qw / 000_100 100_200 200_300 300_400 400_500 500_600
600_700 /;

Using that deweystring list, The program will create the rss files
named the same as the elements of that list (ie "000_100.rss") and
populate them with the correct lines of data. I know how to make the
RSS files (xml::rss etc.).

SO...

I am trying to make a data structure to fit properly and can't get the
syntax right:

I want to make a array of a hashes but the array needs to be named from
that list...so, make an array named @000_100 (I know arrays can't start
with numbers...ideas?) that has a hash with keys "Title" "author"
"ISBN" etc.

So I want to make arrays named after the elements found in the
deweystring list (which everyone says should be done with hashes, and
not variable names) and populate the array with hashes of the data
found in the pipe delimited file....and then get the data back out.

I'll spare you from my code so far since this is a pretty straight
forward question...Can someone write some generic code that would do
something like that? I would REALLY appreciate a little guidance.

Thanks,
Mike
 
U

usenet

mikeybe said:
that list...so, make an array named @000_100 (I know arrays can't start
with numbers...ideas?)

Don't make them individual arrays - use a hash of arrays. The hash keys
can be named whatever you like.
So I want to make arrays named after the elements found in the
deweystring list (which everyone says should be done with hashes, and
not variable names) and populate the array with hashes of the data
found in the pipe delimited file....and then get the data back out.

Are you looking for something like this:

#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;

my %catalog;

$catalog{'000-100'} = [
{'isbn' => '12345', 'dewey' => 'abc123', 'title' => 'foo'},
{'isbn' => '67890', 'dewey' => 'xyz987', 'title' => 'bar'},
];

$catalog{'100-200'} = [
{'isbn' => '77777', 'dewey' => 'ggg777', 'title' => 'baz'},
{'isbn' => '33333', 'dewey' => 'hhh888', 'title' => 'boo'},
];

print Dumper \%catalog;

__END__
 
M

MikeBeccaria

Are you looking for something like this:

YES, exactly...but see below for more details on where I am having
trouble.
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;

my %catalog;

$catalog{'000-100'} = [
{'isbn' => '12345', 'dewey' => 'abc123', 'title' => 'foo'},
{'isbn' => '67890', 'dewey' => 'xyz987', 'title' => 'bar'},
];

$catalog{'100-200'} = [
{'isbn' => '77777', 'dewey' => 'ggg777', 'title' => 'baz'},
{'isbn' => '33333', 'dewey' => 'hhh888', 'title' => 'boo'},
];

The data structure is exactly what I want. I just don't know the syntax
to create this structure using variables from within the program... I
have seen the type of structure you list in books and online...However,
I don't have the data ahead of time to put the information in the way
you listed it. It comes from variables and I want it to so when I want
to change it, I only have to edit the deweystring array. I need to
create the hash keys from a variable name (@deweystring), I need to
dynamically analyze each line to determine which hash key it belongs
in...so if a record had a dewey number of 654 it would be determined
that it belongs in the 600-700 hash key array and the data will need to
be added to that array. I know how to, if given dewey number of 657
return the string from @deweystring "600_700"... I don't know how to
then feed the information into the hash key array with that same name
(i.e. $catalog{'600_700'}).

So, in short, I need to know the syntax of (a) creating the hash names
using the deweystring list (i.e. 000_100 100_200 200_300), (b) adding
the data to the hash arrays on the fly, and (c) extracting the data
from them.

Thanks again,
Mike
 
M

mikeybe

Are you looking for something like this:

YES, exactly. Thanks for the data structure...but see below for more
details on where I am having trouble.
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;

my %catalog;

$catalog{'000-100'} = [
{'isbn' => '12345', 'dewey' => 'abc123', 'title' => 'foo'},
{'isbn' => '67890', 'dewey' => 'xyz987', 'title' => 'bar'},
];

$catalog{'100-200'} = [
{'isbn' => '77777', 'dewey' => 'ggg777', 'title' => 'baz'},
{'isbn' => '33333', 'dewey' => 'hhh888', 'title' => 'boo'},
];

The data structure is exactly what I want. I just don't know the syntax
to create this structure using variables from within the program... I
have seen the type of structure you list in books and online...However,
I don't have the data ahead of time to put the information in the way
you listed it. It comes from variables and I want it to so when I want
to change it, I only have to edit the deweystring array. I need to
create the hash keys from a variable name (@deweystring), I need to
dynamically analyze each line to determine which hash key it belongs
in...so if a record had a dewey number of 654 it would be determined
that it belongs in the 600-700 hash key array and the data will need to
be added to that array. I know how to, if given dewey number of 657
return the string from @deweystring "600_700"... I don't know how to
then feed the information into the hash key array with that same name
(i.e. $catalog{'600_700'}).

So, in short, I need to know the syntax of (a) creating the hash names
using the deweystring list (i.e. 000_100 100_200 200_300), (b) adding
the data to the hash arrays on the fly, and (c) extracting the data
from them.

Thanks again,
Mike
 
U

usenet

mikeybe said:
I only have to edit the deweystring array. I need to
create the hash keys from a variable name (@deweystring), I need to
dynamically analyze each line to determine which hash key it belongs
in...so if a record had a dewey number of 654 it would be determined
that it belongs in the 600-700 hash key array

Since the total number of dewey integers is rather small, I would just
build myself a hash up-front which (for the example you cited) would
have a pair like:
$range{654} = '600-700';
That way, every time I saw a dewey number, I could easily look up what
range it belongs to in that hash by looking at the integer key. I need
to insure consistent handling of leading zeros (either always strip
them or always format them - I took the strip approach - but only for
the internal range look-up; leading zeros are preserved in the output).
The data structure is exactly what I want. I just don't know the syntax
to create this structure using variables from within the program...

How about this:

#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;

my @deweys=qw{000-099 100-199 200-299 300-399 400-499 500-599};
my %range; #quick-lookup to determine dewey range for any integer
foreach my $range(@deweys) {
my ($low, $high) = split(/-/, $range);
$range{int $_} = $range for ($low..$high); #strip leading zeros
}

my %catalog;
while (my $input_line = <DATA>) {
chomp $input_line;
my ($isbn, $dewey, $title, $author) = split(/\|/, $input_line);
push @{$catalog{$range{int $dewey}}}, { #int() strips leading 0
'title' => $title,
'author' => $author,
'isbn' => $isbn,
'dewey' => $dewey,
}
}

#print Dumper \%catalog;

foreach my $range (keys %catalog) {
print "Range: $range\n";
print "\t$$_{'dewey'} - $$_{'title'}\n" for @{$catalog{$range}};
}

__DATA__
01235|003.2|Perl|smith
11111|123.45|php|smith
11111|125.001|Python|smith
22222|345|C++|jones
33333|578|Ruby|brown


I
 
T

Tad McClellan

[ Please provide an attribution when you quote someone. ]

$catalog{'000-100'} = [
{'isbn' => '12345', 'dewey' => 'abc123', 'title' => 'foo'},
{'isbn' => '67890', 'dewey' => 'xyz987', 'title' => 'bar'},
];
The data structure is exactly what I want. I just don't know the syntax
to create this structure using variables from within the program...


perldoc perlreftut

I know how to, if given dewey number of 657
return the string from @deweystring "600_700"... I don't know how to
then feed the information into the hash key array with that same name
(i.e. $catalog{'600_700'}).


Apply "Use Rule 1" from perlreftut:

1) pretend it is a plain array

push @somearray, {'isbn' => '12345', 'dewey' => 'abc123'};

2) replace the name of the array with a block

push @{ }, {'isbn' => '12345', 'dewey' => 'abc123'};

3) put something in the block that returns the right kind of reference

push @{ $catalog{'600_700'} }, {'isbn' => '12345', 'dewey' => 'abc123'};

So, in short, I need to know the syntax of (a) creating the hash names
^^^^^^^^^^

You are befuddling the terminology, which can befuddle your thinking.

There is only _one_ "hash name", and it is "catalog".

I think you meant to ask about creating hash _keys_ rather than hash names?

using the deweystring list (i.e. 000_100 100_200 200_300),


You do not need to create the (top) hash keys.

Just use them, and autovivification will create them for you.

(b) adding
the data to the hash arrays on the fly, and (c) extracting the data
from them.


More applications of "Use Rule 1" should handle those too.
 
A

anno4000

Since the total number of dewey integers is rather small, I would just
build myself a hash up-front which (for the example you cited) would
have a pair like:
$range{654} = '600-700';
That way, every time I saw a dewey number, I could easily look up what
range it belongs to in that hash by looking at the integer key. I need
to insure consistent handling of leading zeros (either always strip
them or always format them - I took the strip approach - but only for
the internal range look-up; leading zeros are preserved in the output).

At this point the module Tie::RangeHash ("Hashes with 'low,high' ranges
as keys") comes to mind. I have never used it, but from the description
it fits the situation exactly.

Anno
 
X

xhoster

Why not just make them 0xx, 1xx, 2xx, 3xx, etc? Especially as the end
point is confusing, it should be 600-699, no?

$dewey =~ /^(\d)\d\d\./ or die "bad dewey $dewey";
my $bin="$1xx";
At this point the module Tie::RangeHash ("Hashes with 'low,high' ranges
as keys") comes to mind. I have never used it, but from the description
it fits the situation exactly.

I've had bad experiences with that module.

Xho
 
D

Dr.Ruud

Jim Gibson schreef:
usenet:

There is redundant information in this array. I would just store the
starting values and use the appropriate comparison operators and
succesive elements in the array to define a range:

my @deweys = qw{ 000 100 200 300 400 500 };

my @deweys = 0..5 ;
;)
 
M

mikeybe

Since the total number of dewey integers is rather small, I would just
build myself a hash up-front which (for the example you cited) would
have a pair like:
$range{654} = '600-700';
That way, every time I saw a dewey number, I could easily look up what
range it belongs to in that hash by looking at the integer key. I need
to insure consistent handling of leading zeros (either always strip
them or always format them - I took the strip approach - but only for
the internal range look-up; leading zeros are preserved in the output).

Good idea up front, however, it causes problems with scalability. For
example, what if I wanted to change my deweystring to make more rss
files and I change it to this:

000-999 010-020 020-030 000-100 100-200 200-300 300-400 400-500 etc.

I would still want this to work. I want the program to work so that
when I change that line to make it as specific as I want, all will
still be well with the world:)

Mike
 
T

Ted Zlatanov

Your requirements are a moving target. You now have overlapping ranges.

I wonder if mikeybe doesn't really want the range to be part of the
RSS feed URL:

/getrss.cgi?start=020&end=030&start=100&end=200

Then dynamically generate the resulting documents, providing some
prebuilt RSS feed queries for users who don't want to build their
own. IIRC the multiple start/end parameters should be OK.

I may be misunderstanding the intent here, but it certainly seems much
more flexible and useful to have ranges as parameters to the RSS query
than fixed ranges.

Ted
 
M

mikeybe

I wonder if mikeybe doesn't really want the range to be part of the
RSS feed URL:

/getrss.cgi?start=020&end=030&start=100&end=200

Then dynamically generate the resulting documents, providing some
prebuilt RSS feed queries for users who don't want to build their
own. IIRC the multiple start/end parameters should be OK.

I may be misunderstanding the intent here, but it certainly seems much
more flexible and useful to have ranges as parameters to the RSS query
than fixed ranges.

Ted

Ted,

I thought about this...and it may be where I end up turning to later
on, but to make a long story short, I'm not doing this now:) The skinny
is that the whole project will be run from a unix box perl script which
will extract the data, create rss feeds from it daily/weekly whatever,
and then FTP the files to the web server. I will make links manually on
the relevant web pages.

Future plans to have them show up in a web page with thumbnails from
amazon etc. At some point it may turn into an email distro list. Who
know...but for now, I need to make this array of hashes of arrays of
arrays of whatever...back to work:) I will, no doubt, have more
questions.

Mike
 
A

anno4000

(e-mail address removed)-berlin.de wrote:
[snip]
At this point the module Tie::RangeHash ("Hashes with 'low,high' ranges
as keys") comes to mind. I have never used it, but from the description
it fits the situation exactly.

I've had bad experiences with that module.

Ah, good to know, thanks for sharing. That won't stop me from giving
it a try, it may have matured.

The idea seems to be: Efficiently set entire ranges of hash keys, retrieve
single values. It looks like a good idea, and obviously it comes up often
enough for you to have given the module a try, for me to at least know
about it. Pity the implementation sucks.

Anno
 
M

mikeybe

Just wanted to let everyone know that I finally got it working
correctly. I couldn't have done it without you so thank you very much!

I ended up making an AoA with the number pair values from @deweystring
[000, 100],
[100, 200],
etc.

Then used those to create a hash of arrays of hashes....crazy junk and
I'm not sure I fully grasp the syntax but it was a learning process.

Thanks again,
Mike
 
T

Ted Zlatanov

I thought about this...and it may be where I end up turning to later
on, but to make a long story short, I'm not doing this now:) The skinny
is that the whole project will be run from a unix box perl script which
will extract the data, create rss feeds from it daily/weekly whatever,
and then FTP the files to the web server. I will make links manually on
the relevant web pages.

One alternate approach you may want to consider is to pre-generate the
smallest chunks, e.g. 020-029, 030-039, etc. as pure data that you can
just include in a bigger result. So your big results will just be an
aggregation of pre-generated small results.

This will have the advantage of predictability. Instead of A to B, C
to D, etc. you will just generate N (1000/10 for example) uniform
pieces of data without any trickery. It will be simpler to understand
and manage than your manually configured ranges, IMHO.

I'm trying to help you with something bigger than the exact approach,
now that I think about it. Try to extract the configuration out of
the code. What you have now requires a code update every time you
change the configuration.

Hope this helps
Ted
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top