Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Peek a hash without breaking iterator

by hurricup (Pilgrim)
on Jun 19, 2016 at 06:33 UTC ( [id://1166063]=perlquestion: print w/replies, xml ) Need Help??

hurricup has asked for the wisdom of the Perl Monks concerning the following question:

Got a problem with peeking hash elements without breaking iterator. According to perldocs, using keys or values on %hash variable resets the internal hash iterator, used by keys/values/each. But seems not only. Simple copying of hash via %other_hash = %hash resets iterator for %hash too.

For example:

my %hash = ('Hello' => 'World'); while ( my ( $key, $value ) = each %hash ) { my %otherhash = %hash; print "\n$key=$value"; }

So question: how can I peek hash keys and values without breaking it?

In case of "why, oh why do you need this?", here is the case: my debugger for IntelliJ IDEA sends current lexical variables to the IDE on each step in/over/etc. And in case of hashes, sends number of elements and elements (by request). But when I'm trying to do so - iterator resets and loop becames infinite. Haven't tried Storable yet, but it seems too expensive anyway.

Replies are listed 'Best First'.
Re: Peek a hash without breaking iterator ( Hash::StoredIterator )
by Anonymous Monk on Jun 19, 2016 at 07:16 UTC
      This works like a charm. Not checked CPAN (don't know why), just googled :) If anyone can suggest other solutions, interested in them all.
Re: Peek a hash without breaking iterator
by karlgoethebier (Abbot) on Jun 19, 2016 at 20:05 UTC

    I guess. What happens if you avoid each?

    foreach my $key ( keys %hash ) { print qq($key => $hash{$key}\n); my %other_hash = %hash; }

    If i run this, i don't get an infinite loop...

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

      If i run this, i don't get an infinite loop...

      Hurricup is writing a debugger, his debugger cannot be rewriting the users code while its running the code, the user isn't going to like that,

        "Hurricup is writing a debugger...rewriting the users code..."

        Yes, sure. It interested me to see what happens, as i wrote. Or should i check out his plugin code (if available) and so on...?

        «The Crux of the Biscuit is the Apostrophe»

        "Hurricup is writing a debugger...rewriting the users code..."

        Yes, sure. It interested me to see what happens, as i wrote. Or should i check out his plugin code (if available) and so on...?

        «The Crux of the Biscuit is the Apostrophe»

Re: Peek a hash without breaking iterator
by choroba (Cardinal) on Jun 21, 2016 at 09:32 UTC
    Have you checked what the other debuggers do? (i.e. Devel::hdb).

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Peek a hash without breaking iterator
by pme (Monsignor) on Jun 19, 2016 at 07:35 UTC
    hi hurricup,

    Excerpts from the man pages:

    each "When called on a hash in list context, returns a 2-element list consisting of the key and value for the next element of a hash."

    keys "Called in list context, returns a list consisting of all the keys of the named hash."

    values "In list context, returns a list consisting of all the values of the named hash."

    As you can see the example below each is executed repeatedly however keys and values are called only once.

    use strict; use warnings; my %hash = ('Hello' => 'World'); while ( my ( $key, $value ) = each %hash ) { #my %otherhash = %hash; print "\n$key=$value"; } print "\n------------------\n"; foreach ( keys %hash ) { my %otherhash = %hash; print "\n$_=$hash{$_}"; } print "\n------------------\n"; foreach ( each %hash ) { my %otherhash = %hash; print "\n$_\n"; } print "\n------------------\n";
      I don't get your point. If you are saying how to modify source code - I know it, but can't do. Check the last paragraph of the question.
Re: Peek a hash without breaking iterator
by anonymized user 468275 (Curate) on Jun 21, 2016 at 08:43 UTC
    If your debugger is incompatible with the 'each' magic, then the options are: use a different debugger, or don't use each.

    A simple way to work around each would be to load it into an array and simulate each as follows:

    $ perl -e ' > my %h=(qw(a b c d e f)); > { my @each = %h; > while (my $k = shift @each) { > my $v = shift @each; > print "$k => $v\n"; > }}' c => d e => f a => b
    Update: you could also create an oo version of each that uses a handler object instead of magic so that it can't break under your circumstances. e.g.
    package OOEach; sub new { my ($class) = @_; return bless {}, $class; } sub each { my $self = shift; $self->{queue} ||= [@_]; # note: will only init once my $k = shift @{$self->{queue}}; my $v = shift @{$self->{queue}}; return ($k, $v); } ;

    One world, one people

      Heheh, another one , hurricup is creating the debugger, hes writing the debugger, he cannot change the users code to suit the debugger,
        Actually he IS changing the user's code to effect debugging. As I understand it he is effectively inserting a command to copy the hash into the code he is debugging. So in fact a custom implementation of each is still one way to stop the real one breaking.

        One world, one people

Re: Peek a hash without breaking iterator
by Cow1337killr (Monk) on Jun 21, 2016 at 21:28 UTC
    ...my debugger for IntelliJ IDEA

    So, let me get this straight. You are using IntelliJ IDEA as your Perl development integrated development environment (IDE).

    (Excuse me if my question shows that I am behind the times.)

Re: Peek a hash without breaking iterator
by shawnhcorey (Friar) on Jun 19, 2016 at 12:19 UTC

    Why do you want to make a copy of the hash inside the loop?

      This is just an example. Please, read the last paragraph.
Re: Peek a hash without breaking iterator
by Anonymous Monk on Jun 20, 2016 at 17:08 UTC

    I guess. What happens if you avoid each?

    foreach my $key ( keys %hash ) { print qq($key => $hash{$key}\n); my %other_hash = %hash; }

    If i run this, i don't get an infinite loop...

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

Re: Peek a hash without breaking iterator
by anonymized user 468275 (Curate) on Jun 21, 2016 at 08:18 UTC
    If your debugger is incompatible with the 'each' magic, then the options are: use a different debugger, or don't use each.

    A simple way to work around each would be to load it into an array and simulate each as follows:

    $ perl -e ' > my %h=(qw(a b c d e f)); > { my @each = %h; > while (my $k = shift @each) { > my $v = shift @each; > print "$k => $v\n"; > }}' c => d e => f a => b

    One world, one people

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1166063]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2024-04-25 18:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found