7

最初,我正在使用长度 = 2^16 的列表。然而,为了抽象这一点,我将在这个例子中设置长度 = 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
4

4 回答 4

4

您可以使用初始化列表吗

@abc = (0) x 2**16 

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

我尝试使用您的 zeroes 方法。如果我像这样初始化数组,它会起作用:

@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;
于 2013-08-06T20:56:55.560 回答
4

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

你可以像这样修复它:

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

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

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

如果您使用过strict并且warnings它会告诉您:

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);
于 2013-08-06T20:57:04.903 回答
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;
}
于 2013-08-06T21:32:37.113 回答
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
于 2013-08-07T04:41:44.780 回答