John W. Krahn wrote:
> Rob Dixon wrote:
> >
> > Well done Kevin!
> >
> > Just a couple of points.
> >
> > Kevin Pfeiffer wrote:
> > >
> > > (I noticed that, too.) But thanks to your tip I think I've
> > > created my first recursive sub-routine (only tested on this
> > > example). If it does what the OP requested (and y'all don't
> > > find too much wrong
> > > with it) then I'm a happy man!
> > >
> > > pad_keys($self);
> > > print Dumper(\$self);
> > >
> > > sub pad_keys {
> > >    my $ref = shift;
> > >    if (ref $ref eq "HASH") {
> > >       for my $value (%$ref) {
> >
> > This will loop over all the keys and values in the
> > hash, in the order key1, value1, key2, value2, ...
> > All you want is the values.
> >
> > >          if (ref $value eq "HASH") {
> > >             pad_keys($value);
> > >          }
> > >       }
> > >       for (keys %$ref) {
> > >          my $old = $_;
> > >          tr/ /_/;
> > >          $ref->{$_} = $ref->{$old};
> >
> > You ought to check whether the new key already exists, otherwise
> > you're going o be losing data.
> >
> > >          delete $ref->{$old};
> > >       }
> > >    }
> > > }
> >
> > Finally, there's no need process the values and then the keys
> > in separate loops. Each execution of either loop corresponds to
> > a key/value pair so you can write
> >
> >   foreach (keys) {
> >     modify key;
> >     recurse on value;
> >   }
> >
> > This is what I came up with. It skips the rest of the loop
> > if the new key is the same as the old one, and uses the
> > fact that 'delete' returns the value of the element it
> > deleted.
> >
> >   sub pad_keys {
> >     my $ref = shift;
> >     return unless ref $ref eq 'HASH';
> >     foreach (keys %$ref) {
> >       pad_keys($ref->{$_});
> >       next unless (my $new = $_) =~ tr/ /_/;
> >       if (exists $ref->{$new}) {
> >         warn "Padded key $new already exists";
> >       }
> >       else {
> >         $ref->{$new} = delete $ref->{$_};
> >       }
> >     }
> >   }
>
> Kevin and Rob,
>
> perldoc -q "add or remove keys from a hash"
>
> Found in /usr/lib/perl5/5.6.0/pod/perlfaq4.pod
>        What happens if I add or remove keys from a hash while
>        iterating over it?
>
>        Don't do that. :-)
>
>        [lwall] In Perl 4, you were not allowed to modify a hash
>        at all while iterating over it.  In Perl 5 you can delete
>        from it, but you still can't add to it, because that might
>        cause a doubling of the hash table, in which half the
>        entries get copied up to the new top half of the table, at
>        which point you've totally bamboozled the iterator code.
>        Even if the table doesn't double, there's no telling
>        whether your new entry will be inserted before or after
>        the current iterator position.
>
>        Either treasure up your changes and make them after the
>        iterator finishes, or use keys to fetch all the old keys
>        at once, and iterate over the list of keys.

As far as I knew this was only a problem with iterating using

  while (my ($k, $v) = each %hash) {
    :
  }

if instead you do

  foreach (keys %hash) {
    :
  }

it's the same as doing

  my @keys = keys %hash;
  foreach (@keys) {
    :
  }

which would be fine here. I would write some code to check but
it's not going to happen tonight!

Cheers,

Rob




-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to