How to set default values?
Let's say I have a hash like this
my %profile = (
building => $p->{account}->{building},
email => $p->{account}->{email},
phone => $p->{account}->{phone},
);
The variables in $p
can have all sorts of values when they have not been defined. I have atleast seen undef
~
''
.
How do I assign a value of -1
to e.g. $profile{building}
if $p->{account}->{building}
have one of these strange default values?
Are there any clever Perl way to do that?
Update: Any of the 开发者_开发技巧values can take on any of the strange default values undef
~
''
.
I would add a function:
my %profile = (
building => scrub($p->{account}->{building}),
email => scrub($p->{account}->{email}),
phone => scrub($p->{account}->{phone}),
);
and implement the default-filtering logic in the function.
Or, better yet, pre-apply the logic to $p so that you know that $p has reasonable values.
So, if I understand you correctly, you have a bunch of bogus things being used as flags for "use the default". I am not sure if you want to translate all of these to -1 or to field specific values. I'll assume multiple values, just to make things trickier.
# Make a hash of the wanted values
my %default_values = (
building => -1,
email => 'N/A',
phone => 'unlisted',
);
# Make a hash of the values to replace.
# Skip undef, we have to check that separately
my %bogus_values = map {$_ => undef} ('', '~', 0);
# Copy the goodies into your final structure
my %profile = map {
my $val = $p->{account}{$_};
$val = $default_values{$_}
if( not defined $val
or exists $bogus_values{$_}
);
$_ => $val;
} keys %default_values;
# Or copy them another way
my %profile = %default_values;
$profile{$_} = $p->{account}{$_}
for grep {
defined $p->{account}{$_}
and not exists $bogus_values{$_}
} keys %default_values;
Starting from Perl 5.10, you can use smart matching:
my @vals = (undef, '~', "");
$profile{building} = $p->{account}{building} ~~ @vals ? -1 : $p->{account}{building};
If using 5.10 or higher I would go with @eugene's solution. Otherwise ...
For untrue values (undef, '', 0) you can do
building => $p->{account}->{building} || -1
For true values you will have to check explicitly, perhaps with a regex:
building => !($p->{account}->{building} =~ m/~|char2|char3/)
? $p->{account}->{building}
: -1
Combining these
building => $p->{account}->{building} || !($p->{account}->{building} =~
m/~|char2|char3/)
? $p->{account}->{building}
: -1
Alternatively, to make this simpler and to facilitate testing and reusability you can extract this logic to a sub:
sub scrub {
my $value = shift;
if (!$value or $value =~ m/~|char2|char3/) {
return -1;
}
return $value;
}
And then
my %profile = (
building => scrub( $p->{account}->{building} ),
email => scrub( $p->{account}->{email} ),
phone => scrub( $p->{account}->{phone} ),
);
This sort of thing will take care of FALSE values (like undef
or ''
or 0
or '0'
or anything else I missed):
my %profile = (
building => $p->{account}->{building} || -1,
email => $p->{account}->{email} || 'N/A',
phone => $p->{account}->{phone} || -1,
);
You can also use the defined-or operator //
, which will only use the default value if undef
is on the left side.
Or to take care of other values:
my %bad_values_hash = map { $_ => 1 } ('~', ''); # Put your bad values in here
my %profile = (
building => ($bad_values_hash{$p->{account}->{building}} ? -1 : $p->{account}->{building}) // -1,
email => ($bad_values_hash{$p->{account}->{email}} ? 'N/A' : $p->{account}->{email}) // 'N/A',
phone => ($bad_values_hash{$p->{account}->{phone}} ? -1 : $p->{account}->{phone}) // -1,
);
(May I suggest refining the design so that it uses more consistent default values?)
精彩评论