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

Perl Newbie here and feeling rather stupid but hoping someone can help me. All I'm trying to do is specify each value within a hash based on some test using conditional code. e.g.

<code> %Weather = ( 'precipitation' => if ($rain == 0) 'dry' Elseif ($rain == 1) 'wet' )

I know I should be able to use the ternary ? as well, but is this just not possible within a hash?

Replies are listed 'Best First'.
Re: Conditional within Hash definition
by tangent (Parson) on Jan 28, 2014 at 16:22 UTC
    Using the ternary operator:
    my $rain = 1; my %Weather = ( 'precipitation' => ($rain == 0) ? 'dry' : 'wet', );
    Or even:
    my $rain = 1; my %Weather = ( 'precipitation' => $rain ? 'wet' : 'dry', );
    The way to use the if/elsif construct:
    my $precipitation; if ($rain == 0) { $precipitation = 'dry'; } elsif ($rain == 1) { $precipitation = 'wet'; }
    See perldoc for Conditional Operator and Compound Statements, and also strict and warnings
      So many thanks - much appreciated!
Re: Conditional within Hash definition
by Random_Walk (Prior) on Jan 28, 2014 at 16:50 UTC

    If you run to more than two conditions, you can use a mapping hash

    use strict; use warnings; # the simple case, as requested my $rain = int rand 2; my %rain_map = ( 0 => 'dry', 1 => 'wet', ); my %Weather = ( precipitation => $rain_map{$rain} ); print "Simple weather($rain) is $Weather{precipitation}\n"; # a little more my $precip = int rand 5; my %precip_map = ( 0 => 'dry', 1 => 'wet fog', 2 => 'wet rain', 3 => 'wet hail', 4 => 'plague of locusts', ); my %More_Weather = ( precipitation => $precip_map{$precip} ); print "More weather($precip) is $More_Weather{precipitation}\n";

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
      Wet rain? that would be the type that soaks you instantly, as opposed to dry rain where even though you can see it you don't seem to get wet. You also have hard and soft rain, and the rain can come in sheets or buckets, or can be spitting, lashing, pissing, driving, teeming, or pelting. And that's all just in one day in Ireland, though we get lots of rainbows too.

        Aye, then we can go off on a tangent about the inuit's alleged 200 words for snow...

        I was actualy using rain as a qualifier for wet, rather than wet as a qualifier for rain. Fog and snow can be wet too. I guess I could have added dry snow if its cold enough too.

        Cheers,
        R.

        Pereant, qui ante nos nostra dixerunt!

      That's really helpful because it was going to be my next question ;) Many thanks!

Re: Conditional within Hash definition
by veryan (Initiate) on Jan 28, 2014 at 16:54 UTC

    ok so I seem to have managed to make it work using x ==y ? 'true' : 'false' format - is it not possible using if and else?

      if(...){...}else{...} is considered a statement rather than an expression. Any expression can be used as a statement, but many statements cannot be used as an expression.

      In a list (which is what a hash is initialized with), the list items are expected to be given as expressions, not statements.

      The ternary operator is an expression, which is why that works.

      A do{...} block allows you to provide a block of statements and wrap it up into an expression:

      my %weather = ( precipitation => do { if ($rain == 0) { "dry"; } else { "wet"; } }, );
      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

        A couple other examples along these lines:

        my ($x, $y, $z) = ( ... ); ... my %weather = ( 'precip' => get_precip_function($x, $y, $z), 'wind_speed' => sub { ... }->($z, $y, $x), ..., );
      You could with a do{} block, but the ternary operator is there and fancier.