Most concise way to assign value from hash only if it exists? - perl

I find myself often writing code like this:
if ($optionalParamsRef->{verbosity}) {
$settingsHash{verbosity} = $optionalParamsRef->{verbosity};
}
However, it seems very verbose to repeat $optionalParamsRef->{verbosity} twice. Is there a shorter way?
Edit: Yes, I realize this is checking for true/false and not 'exists'. What I'm looking for is a concise functional equivalent to this.

Note you are checking $optionalParamsRef->{verbosity} for true, not exist.
Possible way to do this:
foreach my $k (qw/verbosity param1 param2 param3/) { #Enumerate keys here
$settingsHash{$k} = $optionalParamsRef->{$k} if exists($optionalParamsRef->{$k});
}

As others mentioned, your code checks for false-ness. If you considered false values as non-existant, you could have used the logical or. Probably this is not what you want.
$settingsHash{verbosity} = $optionalParamsRef->{verbosity} || $default;
But maybe defined-ness is enough. It's still no check for existence, but if your hash doesn't contain undef values, this could be enough:
$settingsHash{verbosity} = $optionalParamsRef->{verbosity} // $default;
using the "new" defined-or operator // instead of the logical or ||. I know these examples are not equivalent to the code you posted because they alwas assign something, but in my experience, this is often useful, so maybe it could help.

my $v = $optionalParamsRef->{verbosity};
$settingsHash{verbosity} = $v if $v;
for ($optionalParamsRef->{verbosity}) {
$settingsHash{verbosity} = $_ if $_;
}

A concise functional equivalent:
sub {$_[0]=$_[1] if $_[1]}->($settingsHash{verbosity}, $optionalParamsRef->{verbosity});
However, IMO, the main problem with your code is that you are only conditionally setting $settingsHash{verbosity}, keeping you from doing something simpler like:
$settingsHash{verbosity} = $optionalParamsRef->{verbosity} || somedefault
or even:
%settingsHash = ( %defaultSettings, %$optionalParamsRef );

Related

Odd use of False constant in if-then statement

Python is my main language, but have to maintain a rather large legacy Perl codebase.
I have an odd logic statement that I can't make heads or tails over.
At top, a constant is defined as:
use constant FALSE => 0;
sub thisFunc {
FALSE if ($self->{_thisVar} ne "tif");
...
...
return statement,etc..
}
So I'm reading that as a kinda' fancy, non-standard if-then statement,
that if $thisVar string is not equal to "tif", then FALSE. Huh?
Not something like $that = FALSE, just FALSE.
The form of this statement appears in the file several times.
This codebase is in use, and vetted over the years by very good team,
so I think it is valid and has meaning. "use strict;" is set at top.
Could someone be so kind as to explain what is meant by logic.
I've Google'd it but no joy.
Thanks in advance,
"if" logic in Perl can be constructed in couple of ways:
the obvious one:
if ($flag) { do_something() }
less obvious one:
do_something() if ($flag);
This example shows how exactly behaves that odd "FALSE if" statement - which only meaning is found when it is LAST statement in subroutine:
use strict;
use constant FALSE => 0;
sub thisFunc {
my $arg = shift;
FALSE if ($arg ne "tif");
}
print "return val: ".thisFunc("ble")."\n";
print "return val: ".thisFunc("tif")."\n";
output from running above is:
return val: 0
return val:
It is pointless. I suspect it's suppose to be
return FALSE if $self->{_thisVar} ne "tif";
There is a similar construct that isn't pointless. If the loop condition has side-effects, the following isn't pointless:
1 while some_sub();
aka
while (some_sub()) { }
aka
while (1) {
some_sub()
or last;
}
Practical example:
$ perl -E'$_ = "xaabbx"; 1 while s/ab//; say'
xx

Perl set boolean if hash map is empty

I'm just starting out with perl. I want to set a boolean variable flag based on if the hash map has content or not. This tells me I can use a ! operator to check if hash empty. how to check if a hash is empty in perl
So I have this so far:
if (!%someHash){
$flag = false;
} else {
$flag = true;
}
Is this a best way of writing it or there is a simpler way?
Since perl doesn't have boolean types I've always just done:
my $flag = keys %someHash

how to copy(insert) hash reference to another hash reference in perl?

recently started doing perl. I'm reading old code and trying to rewrite some stuff. I've got a question here about hash references.
#declar anon hash ref that will be returned
my $store_hash = {};
foreach my $item (#list)
{
#this will iterate based on list
my $ret_hash = ops_getval($item, $user)
#do some magic here to map $ret_hash into $store_hash
}
ops_getval is a function that returns a type of ref hash. I want to insert those values into $store_hash. How should I approach this? Can I directly do
$store_hash = ops_getval($var1,$var2)
Much appreciated!
I think the standard way to do this is:
#$store_hash{ keys %$ret_hash } = values %$ret_hash;
This merges all of the hashes returned by all of the calls to ops_getval into $store_hash.
An alternate approach that might be clearer to the eye, possibly at the cost of a lot of redundant data copying:
%$store_hash = (%$store_hash, %$ret_hash);
You would do something like:
$store_hash->{$item} = $ret_hash
In general:
$hashref->{$key} = $value
See here for more: http://perldoc.perl.org/perlref.html#Using-References
To be clear, you can use a loop and get this done.
foreach ( keys%{ $ret_hash } ){
$store_hash->{ $_ } = $ret_hash->{ $_ } ;
}

How can I optimize Perl code that checks for directory existence?

sub DirectoryExists {
my $param = shift;
# Remove first element of the array
shift #{$param};
# Loop through each directory to see if it exists
foreach my $directory (#{$param}) {
unless (-e $directory && -d $directory) {
return 0;
}
}
# True
return 1;
}
Is there any way to optimize this code?
Is there any good way to optimize this code?
That algorithm is pretty efficient, because it stops at the first item but you might want to give List::Util::first a try.
use List::Util qw<first>;
#...
return defined first { -e && -d } #$param;
The only major optimization would be that it runs in the C-layer. It's also a pretty recognizable idiom in Perl, and so despite the golf look, the purpose is to "speak perl", not to golf.
List::MoreUtils::any would give you a similar effect and as well, it's a better fit to what you're trying to express: you're asking if any in the array are directories. (a hint though, stack parameter passing is slightly to significantly faster than constructing a reference and passing it--at least in my tests.)
Anyway, here's what it looks like:
return any { -e && -d } #$param;
Means to return true if any satisfy that expression. any often runs in the C-layer, if the module could load its XS version. Otherwise it's "Pure Perl" and probably runs similar to yours.
However, I'm pretty sure you don't have to test for both existence and directory. I'm pretty sure that if the file does not exist, it's not going to be seen as a directory. So, you could collapse it to one condition.
I would write that code as:
sub all_directories_exist {
my $param = shift;
# Remove first element of the array
shift #{$param};
for my $dir ( #{ $param } ) {
return unless -e $directory;
return unless -d _;
}
return 1;
}
I am guessing —although I haven't benchmarked it— one cannot get much faster than that.
Two points:
Do NOT return 0 to indicate failure. You will be surprised if your sub is called in list context.
Are you sure you want to modify the array pointed to by $param?

What is the proper way to check if a string is empty in Perl?

I've just been using this code to check if a string is empty:
if ($str == "")
{
// ...
}
And also the same with the not equals operator...
if ($str != "")
{
// ...
}
This seems to work (I think), but I'm not sure it's the correct way, or if there are any unforeseen drawbacks. Something just doesn't feel right about it.
For string comparisons in Perl, use eq or ne:
if ($str eq "")
{
// ...
}
The == and != operators are numeric comparison operators. They will attempt to convert both operands to integers before comparing them.
See the perlop man page for more information.
Due to the way that strings are stored in Perl, getting the length of a string is optimized.
if (length $str) is a good way of checking that a string is non-empty.
If you're in a situation where you haven't already guarded against undef, then the catch-all for "non-empty" that won't warn is if (defined $str and length $str).
You probably want to use "eq" instead of "==".
If you worry about some edge cases you may also want to check for undefined:
if (not defined $str) {
# this variable is undefined
}
As already mentioned by several people, eq is the right operator here.
If you use warnings; in your script, you'll get warnings about this (and many other useful things); I'd recommend use strict; as well.
The very concept of a "proper" way to do anything, apart from using CPAN, is non existent in Perl.
Anyways those are numeric operators, you should use
if($foo eq "")
or
if(length($foo) == 0)
To check for an empty string you could also do something as follows
if (!defined $val || $val eq '')
{
# empty
}
The rest of answers are complicating things. It's just the following.
If filled:
if ($var) {
}
If not filled:
if (! $var) {
}