如何在Perl中获得一个列表来显示空条目的零?

如何在Perl中获得一个列表来显示空条目的零?,perl,Perl,最初,我正在处理一个长度为2^16的列表。然而,为了抽象这一点,我将在本例中设置length=5 #subroutine to make undefined entries -> 0 sub zeros { foreach(@_) { if(!defined($_)) { $_ = 0; } } } #print out and indicies and elements of list

最初,我正在处理一个长度为2^16的列表。然而,为了抽象这一点,我将在本例中设置length=5

#subroutine to make undefined entries -> 0
sub zeros {
    foreach(@_) {
        if(!defined($_))    {
            $_ = 0;
        }
    }
}       
 #print out and indicies and elements of list 
    sub checking {
        print "List = \n";
        my $counter = 0;
        foreach (@_) { 
            print "index = $counter\n";
            print "$_\n";
            $counter += 1;
        }
            print "\n";
    }
方法1:如果我访问不同的索引来编辑元素,那么在打印数组时会得到以下结果<我不想看到空白。我希望它们为0。我已经设置了一个子例程“zeros”,使未定义的条目变为零。但是我不知道我的代码出了什么问题。我还为列表的每个元素尝试了“$+=0”。我仍然无法为空条目获取零

#method 1
@abc = ();
$abc[1] = 3;
$abc[5] = 5;
&zeros(@abc);
&checking(@abc);
List = 
index = 0

index = 1
3
index = 2

index = 3

index = 4

index = 5
5
方法2:如果我像这样初始化列表,我可以得到零。但正如我所说,我正在处理一个很长的列表,我不能绝对不这样初始化我的列表

#method 2
@abc = (3,0,0,0,5);
&checking(@abc);

List = 
index = 0
3
index = 1
0
index = 2
0
index = 3
0
index = 4
5

你能用电脑初始化你的名单吗

@abc = (0) x 2**16 
哪个选项将其设置为2**16个零的列表

我试过用你的零方法。如果我像这样初始化数组,它会起作用:

@abc = (undef, 1, undef, undef, undef, 5)
sub zeros {
  my @list = @_;
  @list = map { $_ // 0 } @list;
  return @list;
} 

@abc = zeros(@abc);
checking(@abc);
因此,子例程似乎不会替换不存在的数组项(与现有的数组项相反,但其值为
unde

在这种情况下,您可以尝试扩展
子例程以返回修改后的数组并将其分配回原始数组:

#subroutine to make undefined entries -> 0
sub zeros {
    foreach(@_) {
        if(!defined($_))    {
            $_ = 0;
        }
    }
    return @_;
}       

@abc = ();
$abc[1] = 3;
$abc[5] = 5;
@abc = zeros(@abc);
# Check:
print "index = $_\n$abc[$_]\n" for 0..$#abc;
#subroutine to make undefined entries -> 0
sub zeroref {
    my ($array) = @_; # Expect a single argument: An array-reference
    foreach(@$array) {
        if(!defined($_))    {
            $_ = 0;
        }
    }
}       

@abc = ();
$abc[1] = 3;
$abc[5] = 5;
zeroref(\@abc); # Pass an array-reference instead
# Check:
print "index = $_\n$abc[$_]\n" for 0..$#abc;
或者,您可以传递对原始数组的引用:

#subroutine to make undefined entries -> 0
sub zeros {
    foreach(@_) {
        if(!defined($_))    {
            $_ = 0;
        }
    }
    return @_;
}       

@abc = ();
$abc[1] = 3;
$abc[5] = 5;
@abc = zeros(@abc);
# Check:
print "index = $_\n$abc[$_]\n" for 0..$#abc;
#subroutine to make undefined entries -> 0
sub zeroref {
    my ($array) = @_; # Expect a single argument: An array-reference
    foreach(@$array) {
        if(!defined($_))    {
            $_ = 0;
        }
    }
}       

@abc = ();
$abc[1] = 3;
$abc[5] = 5;
zeroref(\@abc); # Pass an array-reference instead
# Check:
print "index = $_\n$abc[$_]\n" for 0..$#abc;

您的方法是正确的,但是
zeros()
函数存在问题。您使用
@abc
作为参数调用它,它将复制该列表。然后更改副本。在子对象的末尾,该副本将被丢弃。在
checking()
函数中,您仍在使用原始列表

您可以这样修复它:

@abc = (undef, 1, undef, undef, undef, 5)
sub zeros {
  my @list = @_;
  @list = map { $_ // 0 } @list;
  return @list;
} 

@abc = zeros(@abc);
checking(@abc);
诀窍是返回修改后的列表并将其重新分配给原始变量

如果您使用了
严格
警告
,它会告诉您:

Use of uninitialized value $_ in concatenation (.) or string at F:\scratch.pl line 28. List =  index = 0

index = 1 3 index = 2

index = 3

index = 4

index = 5 5

Use of uninitialized value $_ in concatenation (.) or string at F:\scratch.pl line 28. 
Use of uninitialized value $_ in concatenation (.) or string at F:\scratch.pl line 28. 
Use of uninitialized value $_ in concatenation (.) or string at F:\scratch.pl line 28.

但是,由于您处理的是一个非常大的数组,我建议使用数组引用,因为复制将非常昂贵

sub zeros {
  $_ //= 0 for @{ $_[0] };
} 

zeros(\@abc);
checking(@abc);
对于5.10%之前的价格

$_ = defined($_) ? $_ : 0 for @abc;
如果要将其转换为函数,请不要返回值,因为替换已就位:

use 5.014;
use strict;
use warnings;
use YAML;

my @abc;
$abc[1] = 3;
$abc[5] = 5;

print Dump \@abc;

map_undefined_entries_to_zeros(\@abc);

print Dump \@abc;

sub map_undefined_entries_to_zeros {
    my $array_ref = shift;
    $_ = defined($_) ? $_ : 0 for @$array_ref;
    return;
}

如果您希望延迟或按需使用零替换undef元素,可以如下所示:

package Ad::Hoc::UndefToZero;

use Tie::Array;
our @ISA = qw(Tie::StdArray);

sub FETCH {
  my ($tied, $i) = @_;
  my $elt = $tied->SUPER::FETCH($i);
  unless (defined $elt) {
    $elt = 0;
    $tied->STORE($i, $elt);   # $tiedarray[$i] is now zero
  }
  $elt;
}

package main;

tie my @abc, 'Ad::Hoc::UndefToZero';
$abc[1] = 3;
$abc[5] = 5;

print "$abc[0]\n";  # $abc[0] now set to zero

你能用
@abc=(0)x2**16
初始化你的列表吗?它将列表设置为2**16个零?你应该始终使用
使用strict;使用警告。这会让你的生活更轻松。小心:当你把它作为一个论据传递时,不会复制该列表。原始元素有别名。@sidyll:如果是这样,为什么OP的原始子
zero
不起作用?它应该会改变别名,不是吗?事实上@sidyll是对的。解释它是如何工作的。只有将
@
赋值给某个对象时,它才会复制值。@辛巴基我正在写一个更详细的答案。@辛巴基我停止了写:-)有一件事我不知道,与数组的初始化方式有关。这是阿德里安·普龙克的回答。如果将别名修改为现有元素,即使将其设置为undef,它也会工作,在OP情况下,它不会工作,因为元素不“存在”。