Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Re^2: Indepedent lazy iterators for the same hash?

by LanX (Saint)
on Jun 30, 2013 at 18:58 UTC ( [id://1041635]=note: print w/replies, xml ) Need Help??


in reply to Re: Indepedent lazy iterators for the same hash?
in thread Indepedent lazy iterators for the same hash?

Any chance to get a (any) solution into core soon?

My hopes were not to rely on dependencies...

update

sorry no time to read all, for my $next (pairs @array) is a real iterator?

This would be very nice mister!!! =)

Cheers Rolf

( addicted to the Perl Programming Language)

Replies are listed 'Best First'.
Re^3: Indepedent lazy iterators for the same hash?
by hdb (Monsignor) on Jun 30, 2013 at 21:00 UTC

    Just an idea: use each as the master iterator somewhere hidden, and have references pointing to the lagging pseudo-iterators. Will try tomorrow to build something.

    UPDATE: Here is my attempt. I am not sure whether it works like each as there is absolutely no magic in it. I am sure it will ignore changes in the hash while you iterating over it.

    use strict; use warnings; sub hashIteratorFactory { my $h = shift; my @both; my $exhausted = 0; return sub { my $i = 0; return sub { my ($k, $v); if( !defined $both[$i] ) { if( !$exhausted and (( $k, $v ) = each %$h) ) { push @both, [ $k, $v ]; } else { $exhausted = 1; $i = 0; return wantarray() ? () : undef(); } } else { ( $k, $v ) = @{$both[$i]}; } $i++; return wantarray() ? ( $k, $v ) : $k; } } } my %h; @h{'a'..'d'} = 1..4; my $factory = hashIteratorFactory( \%h ); my $i1 = $factory->(); my $i2 = $factory->(); print "1:",$i1->(),"\n"; print "1:",$i1->(),"\n"; print "2:",$i2->(),"\n"; print "1:",$i1->(),"\n"; print "1:",$i1->(),"\n"; print "2:",$i2->(),"\n"; print "2:",$i2->(),"\n"; print "1:",$i1->(),"\n"; print "1:",$i1->(),"\n"; print "2:",$i2->(),"\n"; print "2:",$i2->(),"\n"; my $i3 = $factory->(); while( my ($k, $v) = $i3->() ) { print "3:$k$v\n"; } print "2:",$i2->(),"\n"; print "1:",$i1->(),"\n";

    EDIT: added another wantarray ? to the final return line

Re^3: Indepedent lazy iterators for the same hash?
by AnomalousMonk (Archbishop) on Jun 30, 2013 at 20:43 UTC
    ... copying the keys in advance isn't really efficient... My hopes were not to rely on dependencies...

    I don't understand the point about real efficiency, but if you want absolutely no dependencies, you can always roll your own iterator. This one simply stops when it's exhausted, but it's easy to imagine simulating the behavior of the each built-in when it reaches the end of iteration.

    >perl -wMstrict -le "my %hash = qw( one uno two dos three tres four quatro five cinco ); sub my_each (\%) { my $hr = shift; my @k = keys %$hr; ;; return sub { return unless @k; my $k = shift @k; return $k, $hr->{$k}; } } ;; my $e1 = my_each %hash; my $e2 = my_each %hash; ;; print qq{e1: @{[ $e1->() ]}; @{[ $e1->() ]}.}; print qq{e2: @{[ $e2->() ]} \n}; ;; print qq{e1: @{[ $e1->() ]}; @{[ $e1->() ]}.}; print qq{e2: @{[ $e2->() ]} \n}; ;; print qq{e1: @{[ $e1->() ]}; @{[ $e1->() ]}.}; print qq{e2: @{[ $e2->() ]} \n}; ;; print qq{e1: @{[ $e1->() ]}; @{[ $e1->() ]}.}; print qq{e2: @{[ $e2->() ]} \n}; " e1: three tres; five cinco. e2: three tres e1: one uno; two dos. e2: five cinco e1: four quatro; . e2: one uno e1: ; . e2: two dos

    Update: Changed the code example slightly to clarify the termination behavior of the iterator.

      > I don't understand the point about real efficiency,

      Maybe an example helps illustrating the point.

      What is more efficient:

       for (1..1e6) { ... }

      or

       @k=1..1e6; for (@k) {...} ?

      > but if you want absolutely no dependencies,

      I definitely need no dependency b/c this lazy iterator breaks if comparing identical hashes.

      This seems like a trivially avoided case but, what if you working with deeply nested data-structures?

      This effectively means:

      NEVER use each within an iterator operating on a shared data structure, cause it has global side effects!

      > you can always roll your own iterator.

      I'm well aware, thats why asked how to avoid this.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        What is more efficient:
            for (1..1e6) { ... }
        or
            @k=1..1e6; for (@k) {...} ?

        Yes, I see your point, but what I was getting at in asking about real efficiency is that it is my gut feeling (unsupported by any benchmarking: there is no real application to benchmark) that if you have a hash with up to, say, about a million keys, the time to copy those keys into a separate array (as in the example code) will be trivial in comparison the time needed to acutally do with those key/value pairs (as returned by the custom each) whatever it is you want to do with them.

        If you have more than 10 million keys in a hash, you're probably on the verge of moving everything into a database anyway.

        The 10-100 1-10 million key range would seem (again, my gut feeling here) to be where the question of run-time efficiency would come into play, but why cross that bridge before you come to it? (Or are you already standing on that bridge?)

Re^3: Indepedent lazy iterators for the same hash?
by hdb (Monsignor) on Jul 01, 2013 at 10:49 UTC

    I have added another layer of bookkeeping to make it simpler to use assuming that something like HASH(0x7c2300) is a unique identifier for a hash and does not change during runtime.

    use strict; use warnings; sub hashIteratorFactory { my $h = shift; my @both; my $exhausted = 0; return sub { my $i = 0; return sub { my ($k, $v); if( !defined $both[$i] ) { if( !$exhausted and (( $k, $v ) = each %$h) ) { push @both, [ $k, $v ]; } else { $exhausted = 1; $i = 0; return wantarray() ? () : undef(); } } else { ( $k, $v ) = @{$both[$i]}; } $i++; return wantarray() ? ( $k, $v ) : $k; } } } my %hashIteratorStore; sub hashIterator { my $h = shift; die "Not a hash reference!" unless ref $h eq 'HASH'; $hashIteratorStore{$h} //= hashIteratorFactory($h); return $hashIteratorStore{$h}->(); } my %h; @h{'a'..'d'} = 1..4; print \%h,"\n"; my %h2; @h2{'e'..'i'} = 5..8; my $i1 = hashIterator( \%h ); my $i2 = hashIterator( \%h ); print "1:",$i1->(),"\n"; print "1:",$i1->(),"\n"; print "2:",$i2->(),"\n"; print "1:",$i1->(),"\n"; print "1:",$i1->(),"\n"; my $i4 = hashIterator( \%h2 ); print "2:",$i2->(),"\n"; print "2:",$i2->(),"\n"; print "1:",$i1->(),"\n"; print "4:",$i4->(),"\n"; print "4:",$i4->(),"\n"; print "1:",$i1->(),"\n"; print "2:",$i2->(),"\n"; print "2:",$i2->(),"\n"; my $i3 = hashIterator( \%h ); while( my ($k, $v) = $i3->() ) { print "3:$k$v\n"; } print "2:",$i2->(),"\n"; print "1:",$i1->(),"\n";

    This is really only a starting point as it is really read-only. If the hash is changed somewhere inbetween, the cached keys and values will be unmodified. So more work is required.

      Interesting, but the main problem remains that each has global effects.

      So anyone else using each, keys or values on the same hash will reset (and sabotage) the internal iterator.

      After all storing all keys in an array is still the only reliable option. :(

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1041635]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2024-03-29 02:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found