Perl

配列から特定条件「以降」の要素をgrepで取り出す

grepは本来、条件に合う要素だけを配列から取り出す。
でも頑張ればそれだけじゃないこともできるっぽい。

ということで。

@arr1 = qw/pikachu kairyu yadoran pijon/;
@arr2 = qw/kodakku koratta zubatto gyaroppu/;
@arr3 = qw/sandasu menokurage/;

このような文字列配列から、"k"で始まる要素以降の要素をgrepで取り出してみる。

grep_after.pl
#!/usr/local/bin/perl
use strict;
use warnings;

my @arr1 = qw/pikachu kairyu yadoran pijon/;
my @arr2 = qw/kodakku koratta zubatto gyaroppu/;
my @arr3 = qw/sandasu menokurage/;

sub after_k
{
    print $_[0], "\n";
    @_ = eval $_[0];    # 文字列を変数名として使用(printで変数名を表示したかっただけ)
    print "@_\n";

    my $flg = 0;
    @_ = grep { $flg = /^k/ ? 1 : $flg } @_;    # kで始まる要素「以降」の要素を取り出す
    print "@_\n";
    print 'flg: ', $flg, "\n\n";
}

after_k('@arr1');
after_k('@arr2');
after_k('@arr3');

実行結果:

@arr1
pikachu kairyu yadoran pijon
kairyu yadoran pijon
flg: 1

@arr2
kodakku koratta zubatto gyaroppu
kodakku koratta zubatto gyaroppu
flg: 1

@arr3
sandasu menokurage

flg: 0


もちろんここがミソ。

my $flg = 0;
@_ = grep { $flg = /^k/ ? 1 : $flg } @_;    # kで始まる要素名「以降」の要素を取り出す

"k"で始まる要素が来た時にだけフラグを立て、それ以外ではフラグを維持する、という動きを三項演算子でやった。


ちなみに最初はこうしていた。

grep { $flg = /^k/ ? 1 : $flg; $flg > 0 } @_;

しかし、Perlでは0は偽/1は真になるので、この事例ならあえて> 0と明示せずともこれで良いのでは? と思い…

grep { $flg = /^k/ ? 1 : $flg; $flg } @_;

しかし、そんな風に変数をそのまま真偽として渡すなら、わざわざ別途真偽の形にせずともその前で既に$flg =の形で取り沙汰してるんだからそれで代えられるのでは? と思い…

grep { $flg = /^k/ ? 1 : $flg } @_;

というわけで結局こうなったのでした。


他にもmapと組み合わせたりハッシュの何たらを利用したりみたいな方法もありそうだけど、ひとまずこれで。
(ハッシュのことがよくわかってないなんて言えない)


余談。
配列をprintする際、以下が全部違う結果になったのでビビった。

#!/usr/local/bin/perl
use strict;
use warnings;

my @arr1 = qw/pikachu kairyu yadoran pijon/;

print "@arr1\n";
print @arr1, "\n";
print @arr1."\n";

実行結果:

pikachu kairyu yadoran pijon
pikachukairyuyadoranpijon
4