2

有时,我对 APL 的熟悉为我提供了解决问题的算法思想,我用我拥有的语言(例如 Perl)重新实现了这些思想。

所以我已经处理了一个文本文件来创建一个布尔向量,指示分隔文件中使用的字段,现在我想输出那些使用的字段的索引,以及使用的字段的名称。在 APL 中,我会在字段名称向量和字段数量的 iota 上使用 compress 运算符。

在 Perl 中,我这样做了:

my @UsedFieldNames = map { $UsedFields[$_] ? $FieldNames[$_] : () } 0 .. $#UsedFields;

say join " ", map { $UsedFields[$_] ? $) : () } 0 .. $#UsedFields;

其中@UsedFields是一个数组,其中 0 表示未使用,1 表示已使用字段。

  1. 我真的不喜欢使用 map with?:()来模拟压缩 - 有没有更好的方法(我的真实程序在模拟文件的垂直或缩小时第三次这样做)?

  2. 我真的不喜欢在索引上绘制地图以获得结果 - 有没有更好的方法来计算它?(我想一个优化是先计算使用的索引,然后

    @UsedFieldNames = @FieldNames[@UsedIndexes];

4

2 回答 2

4

使用 grep 或 map 的方法是正确的,也是 APL 在幕后使用的方法。您也可以使用子例程将其隐藏在 Perl 中:

sub compress (\@\@) {
    @{$_[0]}[ grep $_[1][$_] => 0 .. $#{$_[1]} ]
#or use:
#   map {$_[1][$_] ? $_[0][$_] : ()} 0 .. $#{$_[0]}
}

my @source = qw(one two three four);
my @ok     = qw(0   1   0     1   );

my @new = compress @source, @ok;

say "@new"; # two four

如果您正在使用数组引用,您还有一些其他的语法选项,在这种情况下,我可能会将其编写为中缀应用程序的标量方法:

my $compress = sub {
    my $src = shift;
    my $ok  = @_ == 1 && ref $_[0] eq 'ARRAY' ? shift : \@_;
    wantarray ?            @$src[ grep $$ok[$_] => 0 .. $#$ok ]
              : sub{\@_}->(@$src[ grep $$ok[$_] => 0 .. $#$ok ])
};

my $source = [qw(one two three four)];
my $ok     = [qw(1   0   1     0   )];

my $new = $source->$compress($ok);

say "@$new"; # one three
say join ' ' => $source->$compress(0, 1, 1, 0); # two three
于 2011-07-26T00:05:12.967 回答
3

其他方法:

my @UsedFieldNames = map { ( $FieldNames[$_] ) x !!$UsedFields[$_] } 0..$#UsedFields;
my @UsedFieldNames = @FieldNames[ grep $UsedFields[$_], 0..$#UsedFields ];
于 2011-07-25T23:21:34.367 回答