简体   繁体   中英

Perl: How to assign a common value to undef elements in an array?

I am building five arrays in perl like (null, null, 32, 54, null, 59). So I first put the values that I know at specific index and fill the others with null. I do this like this

my @p0_series, @p1_series;
$p0_series[2] = "test";
$p1_series[3] = "string";
$p2_series[2] = "hello";
$p3_series[2] = "hi";
for($a = 0; $a < 5; $a++) {
  if(!defined $p0_series[$a]) {
   $p0_series[$a] = null;
  }

  if(!defined $p1_series[$a]) {
   $p1_series[$a] = null;
  }

  if(!defined $p3_series[$a]) {
   $p3_series[$a] = null;
  }

  if(!defined $p4_series[$a]) {
   $p4_series[$a] = null;
  }

  if(!defined $p5_series[$a]) {
   $p5_series[$a] = null;
  }
}

I am trying to reduce this code to simpler one but I am not able to use the variable name p0_series, p1_seires dynamically in a loop. I tried like

for($a=0: $a <5; $a++ ){
if(!defined $p$i_series[$a] ) {
 #  assign values;
}
}

Which is not working. I am new to perl any help is appreciated. Is it possible I can assign the null value to all the undef elements in the array in a simpler manner?

Perl doesn't have null , but it has undef – which incidentally is the default value for unassigned elements in arrays:

my @array = (undef, undef, 32, 54, undef, 59);

creates the same structure as:

my @array;
$array[2] = 32;
$array[3] = 54;
$array[5] = 59;

There is no need to assign the other fields to undef yourself.

If you are trying to assign a default value to elements which are currently undef , you could write something like this (but note the limitations below):

defined or $_ = "default" for @array;

On Perl 5.10 or later, you can use the // defined-or operator:

$_ //= "default" for @array

To assign defaults for multiple arrays:

$_ //= "default" for @array, @other_array

If you want to set an array to a specific length, you can do $#array = $length - 1 , so this actually specifies the highest index. This removes entries from longer arrays. For shorter arrays, the newly created entries will all be undef .


There is a small problem with this: Perl has two kinds of undef :

  • Scalars can contain the value “undef” like my $foo = undef .

    This is the case if we initialize the whole array at once like my @array = (undef, undef, 32, 54, undef, 59) .

  • Unassigned values in arrays or hashes share their undef scalar, which is read-only.

    This is the case when we initialize the array by assigning some indices only, like $array[4] = 2 .

Usually this is no problem, but in a for-loop, the $_ is an alias to the current scalar, which in our case can be readonly. Therefore we can't always do $_ //= "default" for @array but must either:

  • Assign directly into the array element, which creates an assignable scalar in that slot:

     $array[$_] //= "default" for 0 .. $#array; 

    For multiple arrays:

     for my $ref (\\@array, \\@other_array) { $ref->[$_] //= "default" for 0 .. $#$ref; } 
  • Don't assign to the element and create a copy of the array with defaults instead:

     @array = map { $_ // "default" } @array; 

    For multiple arrays:

     @$_ = map { $_ // "default" } @$_ for \\@array, \\@other_array; 

    While I perceive this as more elegant, there can be some problems with this as each array element is copied.

Agreed, but just incase in perl you can also create run-time variable name. As in your case

if(!defined $p$i_series[$a] )

if (!defined ${"p$i"."_series"}[$a] )

This should do the job and create the variable $p1_series[$a] , $p2_series[$a] and further on

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM