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

Dear fellow monks

I have the following code getting a value of a hash. If the element is not existing or zero, I want to assign "1" to a variable, otherwise the value contained in the hash. The code below does the trick, but looks very clumsy :-( . Can you please propose a more elegant solution?

Thanks in advance! Rata

$nr = $metricOpenTasks {$relWeek}{$cc}{"nr"}; $nr = 1 if (!defined ($nr) || ($nr == 0));

update: Updated the description - thanks jethro for finding this mismatch!

Replies are listed 'Best First'.
Re: undefined or zero: loking for an elegant solution
by jethro (Monsignor) on Feb 26, 2010 at 12:40 UTC

    Your description does not match the code. You probably meant "If the element is not existing or zero, I want to assign "1"".

    Wether the one-liner below is really more elegant is in the eye of the beholder, I would think your code looks clean and easy to read

    $nr= $metricOpenTasks {$relWeek}{$cc}{"nr"} ? $metricOpenTasks {$relWe +ek}{$cc}{"nr"} : 1;

    This assumes that empty strings do not occur or should also lead to an assignement of "1"

Re: undefined or zero: looking for an elegant solution
by JavaFan (Canon) on Feb 26, 2010 at 15:51 UTC
    Not existing, or zero:
    $var = !exists $hash{key} || $hash{key} eq "0" ? 0 : 1;
    Undefined (including not existing) or zero:
    $var = ($hash{key} // 0) eq "0" ? 0 : 1;
    False (which includes zero, undefined, non-existing and empty):
    $var = $hash{key} ? 1 : 0;
    Note the eq "0" instead of == 0; this avoids warnings if the keys contains strings that don't look like a number.
Re: undefined or zero: loking for an elegant solution
by shmem (Chancellor) on Feb 26, 2010 at 12:31 UTC
    $metricOpenTasks {$relWeek}{$cc}{"nr"} ||= 1;

    or, if you want to operate on the copy

    ($nr = $metricOpenTasks {$relWeek}{$cc}{"nr"}) ||= 1;
      $nr = $metricOpenTasks{$relWeek}{$cc}{nr} || 1;
        yes *facepalm* of course ;-)

        The construct with parens is necessary for substitution after assignment, not just for plain conditional assignment.

        ($foo = $bar) =~ s/$pat/$subst/; # operates on $foo
Re: undefined or zero: looking for an elegant solution
by 7stud (Deacon) on Feb 26, 2010 at 14:16 UTC

    None of the solutions do what you asked--although they may do what you want. That's because a key can exist, yet its corresponding value is undef:

    use strict; use warnings; use 5.010; my %hash = ( 'one' => undef, ); say "The key 'one' exists" if exists $hash{one}; say "The key 'two' exists" if exists $hash{two}; --output:-- The key 'one' exists

    Note that nothing prints out for the non-existent key: 'two'. Then if you do this:

    $hash{one} ||= 1; say $hash{one}; --output:-- 1
    you will assign 1 to a key that exists--which does not meet your stated requirement.
Re: undefined or zero: looking for an elegant solution
by tigre (Acolyte) on Feb 26, 2010 at 22:36 UTC

    Assuming you truly mean defined and not exists:

    $nr = $metricOpenTasks{$relWeek}{$cc}{'nr'} // 1; $nr = 1 if $nr eq '0';
    (thanks to JavaFan for the tip on using "eq '0'")

    No good way around splitting it into two lines because of checking for the special case of ''. I s'pose you could do something sick like:

    $nr = (($metricOpenTasks{$relWeek}{$cc}{'nr'} // 0) =~ /^($|[^0]|0.)/) +[0] // 1;
    but that doesn't make any sense now does it?