Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to slice only defined values?

I can slice kes/values as next:

$item->%{ @cols }

But if some column does not exist at $item It will be created at resulting hash.

Can I slice only defined values?

like image 207
Eugen Konkov Avatar asked May 19 '21 12:05

Eugen Konkov


2 Answers

You can check whether they exist.

$item->%{ grep {exists $item->{$_}} @cols }

should do the job slicing only the existing values.

Anyway - simply accessing these values should NOT autovivify them. Only if you Pass these values as parameters to some function and they are implicetly aliased there, they are autovivified.

use strict;
use warnings;
use Data::Dumper;

my @cols =qw (a b c);
my $item = [{a => 1, c => 3}];

print Dumper({$item->[0]->%{ grep {exists $item->[0]->{$_}} @cols }});
print Dumper($item);

print Dumper({$item->[0]->%{ @cols }});
print Dumper($item);

print Dumper($item->[0]->%{ grep {exists $item->[0]->{$_}} @cols });
print Dumper($item);

print Dumper($item->[0]->%{ @cols }); ## Only here does autovivication take place
print Dumper($item);

Only the last print will generate the:

$VAR1 = [
          {
            'c' => 3,
            'a' => 1,
            'b' => undef
          }
        ];

indicating that b got autovivified.

like image 133
Georg Mavridis Avatar answered Oct 13 '22 10:10

Georg Mavridis


Use

$item->%{ grep { exists($item->{$_}) } @cols }

or

do { $item->%{ @cols } }

Indexing/slicing a hash does not add elements to it.

my @cols = qw( a b c );
my $item = { };
say 0+%$item;                     # 0
my @kvs = $item->%{ @cols };
say 0+%$item;                     # 0 ok

Except when it's used as an lvalue (assignable value, such as when on the left-hand side of =).

my @cols = qw( a b c );
my $item = { };
say 0+%$item;                     # 0
1 for $item->%{ @cols };
say 0+%$item;                     # 3 XXX

You could filter out the keys of elements that don't exist.

my @cols = qw( a b c );
my $item = { };
say 0+%$item;                     # 0
1 for $item->%{ grep { exists($item->{$_}) } @cols };
say 0+%$item;                     # 0 ok

But the simple solution is to not use it as an lvalue.

my @cols = qw( a b c );
my $item = { };
say 0+%$item;                     # 0
1 for do { $item->%{ @cols } };
say 0+%$item;                     # 0 ok
like image 20
ikegami Avatar answered Oct 13 '22 10:10

ikegami