如何获取列表以在Perl中显示空条目的零?

时间:2013-08-06 20:47:53

标签: 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 
    sub checking {
        print "List = \n";
        my $counter = 0;
        foreach (@_) { 
            print "index = $counter\n";
            print "$_\n";
            $counter += 1;
        }
            print "\n";
    }

方法1 :如果我访问不同的索引来编辑元素,我打印出数组时会得到以下内容。 我不想看到空白。我希望他们为0 。我已经设置了一个子程序“零”来使未定义的条目变为零。但我不知道我的代码出了什么问题。我还为列表的每个元素尝试了“$ _ + = 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

4 个答案:

答案 0 :(得分:4)

您可以使用

初始化您的列表吗?
@abc = (0) x 2**16 

将其设置为2 ** 16个零的列表?

我尝试使用你的零方法。如果我像这样初始化数组:

@abc = (undef, 1, undef, undef, undef, 5)

所以看起来子例程不会替换不存在的数组条目(与现有条件相反,但值为undef

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

#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;

答案 1 :(得分:4)

您的方法是正确的,但您的zeros()功能存在问题。您使用@abc作为参数调用它,该参数生成该列表的副本。然后,您更改副本。在sub的末尾,该副本被丢弃。在checking()功能中,您仍在使用原始列表。

你可以这样解决:

sub zeros {
  my @list = @_;
  @list = map { $_ // 0 } @list;
  return @list;
} 

@abc = zeros(@abc);
checking(@abc);

诀窍是返回修改后的列表并将其重新分配给原始变量。

如果您使用过strictwarnings,那么它就会告诉您:

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);

答案 2 :(得分:1)

use 5.010;
$_ //= 0 for @abc;

对于5.10之前的perls,

$_ = 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;
}

答案 3 :(得分:1)

如果你更喜欢懒惰或按需用零替换undef元素,你可以tie这样的数组:

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