在Perl中实现APL压缩运算符的最佳方法是什么?

时间:2011-07-25 23:09:43

标签: perl apl

有时我的APL熟悉程度为我提供了解决问题的算法思路,我用我所用的语言重新实现 - 例如Perl。

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

在Perl中,我这样做了:

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

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

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

  1. 我真的不喜欢使用带有?:()的地图来模拟压缩 - 是否有更好的方法(我的真实程序在模拟垂直或缩小文件时第三次执行此操作)?< / p>

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

    @UsedFieldNames = @FieldNames[@UsedIndexes];

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:3)

其他方式:

my @UsedFieldNames = map { ( $FieldNames[$_] ) x !!$UsedFields[$_] } 0..$#UsedFields;
my @UsedFieldNames = @FieldNames[ grep $UsedFields[$_], 0..$#UsedFields ];