Perl AtCoderのアップデートを先取りしてライバルに差をつけよう(List::Util他)

# はじめに
[AtCoder：競技プログラミングコンテストを開催する国内最大のサイト](https://atcoder.jp/home) では、言語のアップデートを予定しております。
アップデートにて、[Perlの標準モジュールList::Util](https://perldoc.perl.org/5.30.0/List/Util.html) が増強されたりしますので、今のうちに習得しライバル~~との差を縮め~~に差を付けましょう。

# AtCoder で使用できるList::Util
配列やリストの操作に関する機能が追加されます。

||Perl (v5.18.2)|Perl(v5.26.1)|
|:--:|:--:|:--:|
|reduce|〇|〇|
|any|×|〇|
|all|×|〇|
|none|×|〇|
|notall|×|〇|
|first|〇|〇|
|max|〇|〇|
|maxstr|〇|〇|
|min|〇|〇|
|minstr|〇|〇|
|product|×|〇|
|sum|〇|〇|
|sum0|〇|〇|
|pairs|×|〇|
|unpairs|×|〇|
|pairkeys|×|〇|
|pairvalues|×|〇|
|pairfirst|×|〇|
|pairgrep|×|〇|
|pairmap|×|〇|
|shuffle|〇|〇|
|uniq|×|〇|
|uniqnum|×|〇|
|uniqstr|×|〇|
# product
```product.pl
use List::Util qw(product);
print product 1..6; # => 6! = 720
print product (2, 2, 2, 2, 3, 3, 5); # => 720
```
~~階乗です~~ 総乗でした

```reduce.pl
use List::Util qw(reduce);
print reduce {$a * $b} 1..6; # => 6! = 720
print reduce {$a * $b} (2, 2, 2, 2, 3, 3, 5); # => 720
```
reduce でも同じ計算が可能です
# pairs
1次元配列を2つの要素で利用します。
[AtCoder Beginner Contest 151 C - Welcome to AtCoder](https://atcoder.jp/contests/abc151/tasks/abc151_c)

```C.pl
use strict;
use warnings;
use 5.26.1;
use List::Util qw(pairs pairgrep pairkeys pairvalues uniq sum0);

my ($n, $m);
{
  my $in = <STDIN>;
  ($n, $m) = split(" ", $in);
}
my @p;
for (my $i=0; $i<$m; $i++) {
  @p = (@p, split " ", <STDIN>); 
}
my @c = uniq pairkeys pairgrep {$b eq 'AC'} @p; 
my (%d, %e);
for my $i (@c) {
  $d{$i} = 1;
  $e{$i} = 0;
}
for my $pair (pairs @p) {
  if ($pair->value eq 'WA') {
    if ($d{$pair->key}) {
      $e{$pair->key}++;
    }
  } else {
    $d{$pair->key} = 0;
  }
}
say scalar @c, " ", sum0 pairvalues %e;
```
例えば、**@p = (1, WA, 1, AC, 2, WA, 2, AC, 2, WA);** と何の変哲もない配列ですが、**pairs @p** としますと次のように扱うことができます。

|pairkeys|pairvalues|
|:--:|:--:|
|1|WA|
|1|AC|
|2|WA|
|2|AC|
|2|WA|
```uniq.pl
my @c = uniq pairkeys pairgrep {$b eq 'AC'} @p; # => @c = (1, 2)
```
ここでは、**@p** を **pair化**し $b (**pairvalues** 側)を 'AC' で **grep** します。
更に、**pairkeys** 側を取り出して **uniq** で重複を削除しています。
# tuple 的な手法
同じく、[AtCoder Beginner Contest 151 C - Welcome to AtCoder](https://atcoder.jp/contests/abc151/tasks/abc151_c)

```tuple.pl
use strict;
use warnings;
use 5.26.1;
use List::Util qw(pairs pairgrep pairkeys pairvalues uniq sum0);

my ($n, $m);
{
  my $in = <STDIN>;
  ($n, $m) = split(" ", $in);
}
my @p;
for (my $i=0; $i<$m; $i++) {
  @p = (@p, split " ", <STDIN>); 
}
my @c = uniq pairkeys pairgrep {$b eq 'AC'} @p; 
my %d;
for my $i (@c) {
  $d{$i} = [1, 0];
}
for my $pair (pairs @p) {
  if ($pair->value eq 'WA') {
    if ($d{$pair->key}[0]) {
      $d{$pair->key}[1]++;
    }
  } else {
    $d{$pair->key}[0] = 0;
  }
}
my $sum = 0;
for my $key (keys %d) {
  $sum += $d{$key}[1];
}
say scalar @c, " ", $sum;
```
```tuple.pl
for my $i (@c) {
  $d{$i} = [1, 0];
}
for my $pair (pairs @p) {
  if ($pair->value eq 'WA') {
    if ($d{$pair->key}[0]) {  # => key 問目の AC フラグ
      $d{$pair->key}[1]++;    # => key 問目の WA カウント
```
ハッシュ %d の **value** 側に配列のリファレンスを渡すことにより、3つ以上の要素から成る「組」を生成しています。

# feature プラグマ
[こちらのQiita](https://qiita.com/xtetsuji/items/a21c718ca37799d11c7c) に詳しいのですが、先頭で、

```use.pl
use feature qw(say state bitwise);
```
と宣言すると、**say** **state** **bitwise** が使用可能となります。

||説明|
|:--:|:--:|
|say|末尾改行付き print|
|state|競プロとしては、変数の重複回避|
|bitwise|ビット演算子の拡張|
```feature.pl
use feature qw(say state bitwise);

sub count1 {
  state $c = 0;
  ++$c;
}
sub count2 {
  state $c = 0;
  ++$c;
}
say count1(); # => 1
say count1(); # => 2
say count2(); # => 1

say "1001" | "0010"; # => 1003
say "1001" |. "0010"; # => 1011
no feature qw(bitwise);
say "1001" | "0010"; # => 1011
```

# まとめ
+ やはりC++のチート具合が凄い
+ でも Perlもいい線いっている
+ tani-ro-hei さん、List::Util の pair を教えていただき、ありがとうございました。

参照したサイト

+ [Perlの標準モジュールList::Util](https://perldoc.perl.org/5.30.0/List/Util.html)
+ [厳選！Perl アルゴリズム実装に使える 25 の 標準ライブラリ【前編】](https://qiita.com/superrino130/items/ab266b53f85c181b369d)
+ [Perl の文法上の新機能が使える feature プラグマ詳解](https://qiita.com/xtetsuji/items/a21c718ca37799d11c7c)

# 追記
**product** は階乗ではなく総乗でした。
*[各メジャーバージョンの Perl に同梱されている List::Util で使える関数一覧](https://qiita.com/xtetsuji/items/4d9bd6b6d07cd5ca6801)*

```mod.pl
use List::Util qw(reduce);
print reduce {$a * $b % 1000000007} 1..100; # => 437918130
```
競プロ目線ですと、**reduce** の方が使用頻度が高そうな気がします。