有时我的APL熟悉程度为我提供了解决问题的算法思路,我用我所用的语言重新实现 - 例如Perl。
所以我处理了一个文本文件来创建一个布尔向量,指示分隔文件中的已用字段,现在我想输出那些用过的字段的索引,以及所用字段的名称。在APL中,我将使用压缩运算符而不是字段名称的向量,以及字段数量的iota。
在Perl中,我这样做了:
my @UsedFieldNames = map { $UsedFields[$_] ? $FieldNames[$_] : () } 0 .. $#UsedFields;
和
say join " ", map { $UsedFields[$_] ? $) : () } 0 .. $#UsedFields;
其中@UsedFields
是一个数组,其中0表示未使用,1表示已用字段。
我真的不喜欢使用带有?:()
的地图来模拟压缩 - 是否有更好的方法(我的真实程序在模拟垂直或缩小文件时第三次执行此操作)?< / p>
我不喜欢在索引上做地图以获得结果 - 有更好的方法来计算吗? (我想一个优化是首先计算使用的索引,然后
@UsedFieldNames = @FieldNames[@UsedIndexes];
答案 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 ];