in reply to Re: Hash/Array slice : how to exclude items?
in thread Hash/Array slice : how to exclude items?

I would create a shallow copy and delete the keys there

An alternative:

sub debug_hash ( $hashref, $bad_keys = [qw/ schema logger /] ) { delete local @$hashref{ @$bad_keys }; print Dumper $hashref; }

Replies are listed 'Best First'.
Re^3: Hash/Array slice : how to exclude items?
by choroba (Cardinal) on Jan 24, 2023 at 16:30 UTC
    delete local requires 5.12 (as mentioned in the link you provided, too, I just think it's worth mentioning here).

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re^3: Hash/Array slice : how to exclude items?
by bliako (Abbot) on Jan 24, 2023 at 22:44 UTC

    delete local looks promising, thanks haukex and ikegami. If only delete returned the remaining hash. Shouldn't this work?: print Dumper(do { delete local  @$hashref{ @$bad_keys }, $hashref} ); or this print Dumper(do { delete local  @$hashref{ @$bad_keys }; $hashref} ); My intention is to delete the elements of the local hash, pass that to Dumper and hopefully leave it untouched when Dumper returns.

    my @unwanted = qw( schema log ); my %hash = (schema=>1, log=>2, aa=>3); print Dumper(delete local @hash{ @unwanted }, \%hash); print Dumper(\%hash); $VAR1 = 1; $VAR2 = 2; $VAR3 = { 'aa' => 3 }; $VAR1 = { 'aa' => 3 };
    my @unwanted = qw( schema log ); my %hash = (schema=>1, log=>2, aa=>3); print Dumper(do { delete local @hash{ @unwanted }; \%hash }); print Dumper(\%hash); $VAR1 = { 'aa' => 3, 'log' => 2, 'schema' => 1 }; $VAR1 = { 'aa' => 3, 'log' => 2, 'schema' => 1 };

      delete returns the thing(s) deleted, not the things remaining after deletion, so that idea won't fly.

      The effect of local is undone at the end of the block (scope) in which it was done, so your proposed examples cannot work - the elements have already been restored by the time Dumper() gets a look at the hash.

      If you can put the Dumper() call inside the block, then it will work:

        print do { delete local @$hashref{ @$bad_keys }; Dumper($hashref) };

      For a complete example:

      % perl -we '%a=(schema=>1,log=>2,aa=>3); use Data::Dumper; print do { delete local @a{qw{ schema log }}; Dumper(\%a) }' $VAR1 = { 'aa' => 3 }; %

        yes I was trying to return the local copy really. But as you said it gets restored.

      > Shouldn't this work?:

      > print Dumper(do { delete local  @$hashref{ @$bad_keys }, $hashref} ); or this print Dumper(do { delete local  @$hashref{ @$bad_keys }; $hashref} );

      yes it's surprising.

      One needs to remember that local is protecting certain entries and not the whole hash (The hash could be a lexical variable, local wouldn't do anyway)

      Since you are returning a reference, you'll see the restored entries again after leaving the block.

      consider what's happening without delete

      DB<91> use Data::Dump qw/pp/ DB<92> ; {local @hash{qw/log schema/};say pp \%hash}; say pp \%hash { a => 1, b => 2, c => 3, log => undef, schema => undef } { a => 1, b => 2, c => 3, log => "l", schema => "s" }

      you can still have the desired effect by just returning a list or a new anonymous hash

      DB<96> say pp do {delete local @hash{qw/log schema/}; %hash }; say +pp \%hash ("a", 1, "c", 3, "b", 2) { a => 1, b => 2, c => 3, log => "l", schema => "s" } DB<97> say pp do {delete local @hash{qw/log schema/}; +{%hash} }; s +ay pp \%hash { a => 1, b => 2, c => 3 } { a => 1, b => 2, c => 3, log => "l", schema => "s" } DB<98>

      if you shy away from the overhead to return a new hash, just do the dumping inside the block.

      DB<99> ; {delete local @hash{qw/log schema/};say pp \%hash}; say pp +\%hash { a => 1, b => 2, c => 3 } { a => 1, b => 2, c => 3, log => "l", schema => "s" } DB<100>

      HTH! :)

      Cheers Rolf
      (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
      Wikisyntax for the Monastery

        if you shy away from the overhead to return a new hash,

        yes, that's one of my fetishes. But as you and hv said: do the printing in the block. It sounds a bit excessive but it seems a good candidate now, along with the slice-with-grep-keys. Given that I may use a number of "printers" : print, say, Dumper, Mojo::Log, then I would not want a special sub which hardcodes the logger.

        One purpose of this post was to nudge Perl language developers to consider exclude-slices, with maximum elegance and minimum overhead (Logging like this happens every few lines of code for me). Btw, the negation with ! looks nice.

        Btw2, is anyone aware of another language implementing this? I googled pithon and did not see something.