6

I am building an array of hashes of arrays

my @array = (
    {label => 'first hash'},
    {label => 'second hash',
     innerarray => [
        {label => 'first inner hash'},
        {label => 'second inner hash'},
      ]
    },
);

Is there a way to only add the second inner hash only if a condition is fullfilled? Something like this:

my @array = (
    {label => 'first hash'},
    {label => 'second hash',
     innerarray => [
        {label => 'first inner hash'},
        {label => 'second inner hash'} if 1==1,
      ]
    },
);

I tried to rewrite my code using push:

my @innerarray = ();
push @innerarray, {label => 'first inner hash'};
push @innerarray, {label => 'second inner hash'} if 1==1;

my @array = (
    {label => 'first hash'},
    {label => 'second hash',
     innerarray => \@innerarray
    },
);

But it becomes very illegible, as I have to predefine all inner array before using them, which in some cases is several 100 lines of code above the usage.

Is there any way to add the if-condition directly where I insert the array-element?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Pit
  • 1,448
  • 1
  • 18
  • 26

4 Answers4

9

Use the conditional operator, it is usable as expression.

my @array = (
    {label => 'first hash'},
    {
        label      => 'second hash',
        innerarray => [
            {label => 'first inner hash'},
            (1 == 1)
                ? {label => 'second inner hash'}
                : (),
        ]
    },
);
ikegami
  • 367,544
  • 15
  • 269
  • 518
daxim
  • 39,270
  • 4
  • 65
  • 132
  • 1
    "Ternary operator" isn't its name, it's just a description of how many operands it takes. The conditional operator is not Perl's only ternary operator. (e.g. `dbmopen`) Fixed. – ikegami May 02 '12 at 15:54
6

You are storing an array reference in your innerarray (example 1) but in your rewrite you try to store the array.
Try this instead:

my @innerarray = () ;
push @innerarray, {label => 'first inner hash'};
push @innerarray, {label => 'second inner hash'} if 1==1; # Not a real condition ...

my @array = (
    {label => 'first hash'},
    {label => 'second hash',
     innerarray => \@innerarray
    },
) ;

And you were also missing a ; twice.

And for your question on inlining some content ...

my @array = (
    {label => 'first hash'},
    {label => 'second hash',
     innerarray => [
        {label => 'first inner hash'},
        ( $condition == 1 ? {label => 'second inner hash'} : () ) ,
      ]
    },
) ;
dgw
  • 13,418
  • 11
  • 56
  • 54
3

You can do:

#!/usr/bin/env perl

use strict; use warnings;

my @array = (
    {label => 'first hash'},
    {label => 'second hash',
     innerarray => [
        {label => 'first inner hash'},
        1 == 0 ? {label => 'second inner hash'} : (),
      ]
    },
);

use YAML;
print Dump \@array;

Output:

---
- label: first hash
- innerarray:
    - label: first inner hash
  label: second hash

But, why?

You can also do:

    ({label => 'second inner hash'}) x (1 == 0),

but, again, why?

Specifically, embedding this in the initialization of the data structure visually hides what's happening from the reader of the code. If the conditions are even slightly complicated, you're bound to introduce hard to trace errors.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
3

In addition to the conditional operator ( and sometimes in combination with it), map is often useful in similar circumstances.

my @labels = (
    'first inner hash',
    'second inner hash',
);

my @array = (
    {label => 'first hash'},
    {
        label      => 'second hash',
        innerarray => [
            ( map { { label => $_ } } @labels ),
        ]
    },
);
ikegami
  • 367,544
  • 15
  • 269
  • 518