配列内の値の合計値をワンライナーで書く (sum of array) #perl

Moscow.pm のメーリングリスト の話題が面白かった。
Perl には、map や grep みたいに美しく配列処理できる強力な関数があるのに、sum とか avg みたいな集約系の関数は用意されておらず、自前で書く必要がある。
『計算用の変数 $sum を使わずに、配列の値の和を計算する方法』というのがお題です。元のポスト のロシア語の本文は読めないけど、Perl は読めるのが楽しい。(翻訳)
Aleksander Gorohovskiさん:
my $sum;
$sum += $_ for @m;
うんうん、こういうの書きますよね?
例えば 1, 2, 3 を足すと、6 が出てくる。
以下、ワンライナーで実行しやすいように一部変更済です。(配列の値は 1~3 に統一)
Alexander Onokhovさん:
perl -MList::Util=sum -le 'print sum 1,2,3'
List::Util モジュールを使った例。ふむふむ。
Perl モジュール利用の教科書的?
再び Alexander Onokhov さん:
perl -le 'print eval join "+", 1,2,3'
反対に「こう書いてはいけない」例のようなコード。(笑)
Maxim Vuetsさん:
perl -E 'sub funcsum { @_ > 1 ? funcsum(@_[1..$#_]) + $_[0] : $_[0] } say funcsum(1,2,3)'
変数を使わないために、わざわざ関数を再帰コールする。コードが長くなった。w
Alexander Onokhovさん:
perl -le 'print length join "", map 1 x $_, 1,2,3'
だんだん変態コードになってくる。文字列長を数える。
こういうの好きです。
Alexander Onokhovさん:
perl -le 'print do { sleep $_ for 1,2,3; time - $^T }'
sleep して、起動時刻 $^T からの実行時間を表示するコード。
つまり、結果の値の秒数だけ、処理時間がかかります。
Denis Evdokimovさん:
perl -le '@m = (1,2,3); $m[0]+= pop @m while @m > 1; print $m[0]'
中間変数は使わない代わりに、配列自体を破壊するコード。
Denis Ibaevさん:
perl -le 'print unpack "%W*", join "", map chr, 1,2,3;'
なんだこれ?
W は、An unsigned char value。
調べてみると、unpack は % で16ビットのチェックサム(値の和)が出せるらしい。
合計値が16ビットの範囲に収まるなら、これでいいんだ。へぇ!
もう20世紀から Perl を使ってるけど、こんな機能も使う場面も初めてみたヨ。
Oleg Alistratovさん:
perl -le 'print unpack("%32d*", pack "d*", (1,2,3))'
d で倍精度浮動小数点にしたバージョン。%32 で、32ビットまで対応。
Dmitry Karasikさん:
perl -le 'print sub { (map {splice @_, 0, 2, $_[0] + ($_[1] // 0)} @_)[-1] }-> (1,2,3);'
もう変態過ぎて、読む気がしない。
Andrew Shitovさん:
perl6 -e 'say [+] 1,2,3'
Perl 6 だと簡単になるらしい。
僕の Mac には Rakudo はインストールしていないので、 Dan さんのマシンをお借りする と結果が出た:
{"lang":"/usr/local/perl6/rakudo-star-2011.04/install/bin/perl6","status":0,"stderr":"","stdout":"6\n","syscalls":27096,"time":2.38981294631958}
添削求ム。
この記事へのコメント
sub sum { @_ ? shift() + &sum : 0 } print sum 1, 2, 3;
あと、joinしてlengthを配列版にすると、
print 0+@{[map+((0)x$_), 1, 2, 3]}