Help - Search - Member List - Calendar
Full Version: Perl Hash Question.
WorkTheWeb Forums > Webmaster Resources > Perl Beginner Help
Support our Sponsors!
Anthony Roe
Hi there everybody, I have a question and I am pretty stumped for the answer.

I have a program that does the following:

A = Reads URI from URIHASH.
Visits site A.
Parses all URIS on site A and for each URI found adds the URI to the URIHASH.

A = Reads next URI from URIHASH.
Visits site A.

And so on... until the MAX URIHASH size is reached.

My question is, is there any way to iterate through a hash in this manner.

I tried foreach():

foreach $key (keys %URIHASH){}

and this does not work. What occurs is the entry that exists in the
URIHASH when the foreach loop is entered, is processed.
any additional entries that are added during the loop are not processed.

I also tried each():

while (($key, $entry) = each %URIHASH){}

When additional entries are added during the loop, this seems to
produce unexpected behaviour. In my case an infinite loop.


I should also mention that the URIHASH is tied to a file on the disk.

Any help at all would be appreciated.

Thank you very much.

Xavier Noria
On Jun 24, 2005, at 5:07, Anthony Roe wrote:

QUOTE
A = Reads URI from URIHASH.
Visits site A.
Parses all URIS on site A and for each URI found adds the URI to
the URIHASH.

A = Reads next URI from URIHASH.
Visits site A.

And so on... until the MAX URIHASH size is reached.

My question is, is there any way to iterate through a hash in this
manner.

I tried foreach():

foreach $key (keys %URIHASH){}

You don't see the changes because

keys %URIHASH

returns the list of keys *once*, when the foreach is entered. That
list is kept in memory, it is not recomputed in each iteration. So
you are modifying %URIHASH just fine, but iterating over the old list
of keys.

QUOTE
and this does not work. What occurs is the entry that exists in the
URIHASH when the foreach loop is entered, is processed.
any additional entries that are added during the loop are not
processed.

I also tried each():

When a program iterates over a hash it can't modify it. That's the idea.

That happens in general to collections no matter the programming
language because of their underlying implementations and the ones for
iterators. One needs to check the documentation about it to see
what's allowed in each case.

When you are iterating in Perl over a hash with each(), the only
valid modification (and so an exception to the rule stated above) is
a case of delete. From perldoc -f each:

If you add or delete elements of a hash while you're
iterating over it, you may get entries skipped or duplicated,
so don't. Exception: It is always safe to delete the item most
recently returned by "each()", which means that the following
code will work:

while (($key, $value) = each %hash) {
print $key, "n";
delete $hash{$key}; # This is safe
}

A solution for your program is to maintain some sort of auxiliar hash
or array, sometimes it makes sense to merge it with the hash after
each iteration, sometimes not, depending on the program. For
instance, something like this:

my @uris = keys %URIHASH;
while (@uris) { # checks size, no problem
my $uri = shift @uris; # short @uris by one
push @uris, @newuris; # add uris to the array
@URIHASH{@newuris} = (1) x @newuris; # merge them in the hash
}

That's an example, but anyway you see why this happens and what needs
to be fixed.

-- fxn


PHP Help | Linux Help | Web Hosting | Reseller Hosting | SSL Hosting
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2005 Invision Power Services, Inc.