On Fri, Jul 12, 2002 at 10:39:08AM +0200, Bodo Eing wrote:
> On 11 Jul 2002, at 15:02, Jeff Zucker wrote:
> 
> > Pomin Wu wrote:
> > 
> > > When accessing CSV with AnyData as a tie hash, I found
> > > that although the C<while (my $row = each %$table)> syntax
> > > is valuable, it C<last> as soon as I try to modify the
> > > table inside the loop, for ex. C<delete $table->{key};>.
> > > Or have I missed something?
> > 
> > 
> > Not sure what you mean.  This works:
> > 
> >    use AnyData;
> >    my $table = adTie( 'CSV', ["id,phrase\n1,foo\n2,bar\n3,baz"] );
> >    while (my $row=each %$table) {
> >       delete $table->{$row->{id}}
> >              if $row->{id}<3 and $row->{phrase} ne 'bar';
> >    }
> > 
> > But if all you want to do is delete a set of rows, you don't need the
> > while loop, you can just do something like this which accomplishes the
> > same thing as the while loop above:
> > 
> >    delete $table->{{id=>'< 3',phrase=>'ne bar'}};
> > 
> > If I've misunderstood your question, please send an example of the
> > offending code.
> > 
> > -- 
> > Jeff
> > 
> 
> Although it may work for this particular case, I consider it critical 
> to edit hashes while iterating over them with the while/each 
> construct. Although deleting is "officially" allowed (see perlfaq4) 
> for conventional hashes since perl5, and changing the current value 
> is also possible, this can get you into trouble with tied hashes 
> (e.g., changing the values of a hash tied to MLDBM during iteration 
> with while/each can bomb you into an infinite loop). In general, I 
> think that while/each is for fast read-only access, and for/keys for 
> editing purposes.
> 
> Bodo
> 
> 
> 

Yes, I tried out some code as suggested.  It seems the foreach/keys
construct does not have this problem.  This is the result:


use AnyData;

my $table = adTie 'CSV', ["name,class,total\nSam,normal,18\nMary,normal,278"]
    or die "can't adTie: $!";

while (my $row = each %$table) {
    print "$row->{name}\n";

    # this would stop after 'Sam'
    $table->{{ name => $row->{name} }} = {total => 1};

    # this also
    #$row->{name} .= '0';
    #$table->{$row->{name}} = $row;

    # but this works
    #delete $table->{$row->{name}};
}


foreach my $row (keys %$table) {
    print "$row->{name}\n";

    # this works
    $table->{{ name => $row->{name} }} = {total => $row->{total} + 1};

    # this also
    #$row->{name} .= '0';
    #$table->{$row->{name}} = $row;

    # and of course this
    #delete $table->{$row->{name}};
}



/pm5/

Reply via email to