やっさんの雑記

プログラミングでやってみたこととか

配列の要素の和

何か配列を用意したとき、その配列の要素すべての和を求めたいことはよくありますね。

そのとき、すべての要素が数値型(intとかfloatとか)なら特に問題はないんですが、stringの配列だったりだとか、2次元配列だったりとかすると事態は複雑です。スクリプト言語とかで配列の要素の型が1種類じゃない場合はもっと複雑ですね。

そこで、私の独断と偏見で選んだ代表的なスクリプト言語4つの「配列の要素の和を求める標準関数」を使って、下の4つの配列の要素の和をそれぞれ求めてみました。

a = [1, 2, 3, 4, 5, 6]
b = [1, "2", 3, 4, 5, 6]
c = [1, 2, 3, 4, [5, 6]]
d = [1, "2", 3, 4, [5, 6]]

Ideone上でためしに実行するとこんな感じになります。スクリプト言語はあまり好きではないのでよく知らないのですが、変な書き方などしているところがあったらご指摘ください。

Perl

use strict;
use List::Util qw(sum);

my @a = (1, 2, 3, 4, 5, 6);
my @b = (1, "2", 3, 4, 5, 6);
my @c = (1, 2, 3, 4, (5, 6));
my @d = (1, "2", 3, 4, (5, 6));
print List::Util::sum(@a), "\n"; # => 21
print List::Util::sum(@b), "\n"; # => 21
print List::Util::sum(@c), "\n"; # => 21
print List::Util::sum(@d), "\n"; # => 21

Perlは入れ子になった配列でも再帰的に和を計算してくれるらしいです。
文字列も数値に変換した上で合計を計算してくれています。

PHP

<?php
$a = array(1, 2, 3, 4, 5, 6);
$b = array(1, "2", 3, 4, 5, 6);
$c = array(1, 2, 3, 4, array(5, 6));
$d = array(1, "2", 3, 4, array(5, 6));
echo array_sum($a) . "\n"; # => 21
echo array_sum($b) . "\n"; # => 21
echo array_sum($c) . "\n"; # => 10
echo array_sum($d) . "\n"; # => 10
?>

こちらはPerlと違って入れ子の配列は再帰的に和を計算するとかはせず、単に0扱い(or 単に足さないだけ)らしいです。

Python

a = [1, 2, 3, 4, 5, 6]
b = [1, "2", 3, 4, 5, 6]
c = [1, 2, 3, 4, [5, 6]]
d = [1, "2", 3, 4, [5, 6]]
print sum(a), "\n" # => 21
# print sum(b), "\n" # => error
# print sum(c), "\n" # => error
# print sum(d), "\n" # => error

お行儀がいいと言いましょうか、最初の数字だけの配列以外はすべてREになりました。

Ruby

a = [1, 2, 3, 4, 5, 6]
b = [1, "2", 3, 4, 5, 6]
c = [1, 2, 3, 4, [5, 6]]
d = [1, "2", 3, 4, [5, 6]]
puts a.inject(:+) # => 21
# puts b.inject(:+) # => error
# puts c.inject(:+) # => error
# puts d.inject(:+) # => error

Pythonと同じ結果です。

まとめ

ということで適当にアルファベット順に実行してみたわけですが、PythonRubyは配列に「変なもの」が入っていても型付けの強さのおかげですぐREを出してくれます。

Perlの仕様は1次元配列だけではなくて多次元配列の全要素の和を求めたいときなどにはとても楽に書けるようになっているんじゃないかと思います。しかし、下手に無理やり答えを計算しようとしちゃっているので、「一応エラーは出ないけど答えが正しくない」とかいう一番厄介なパターンのバグを含みやすそうな気がします。

PHPの仕様は誰得なんでしょうね。数値型じゃない要素は足さないという仕様ならまだしも、文字列型のものは数値型に変換して足しちゃってるので、便利になりそうなケースも思い浮かばないですし、Perlでの一番厄介なバグも含みやすそうです。数値型にできないものは足さないというのは内部の実装としてはわりと簡単そうですが。


まあそもそも配列にぐちゃぐちゃいろんな型の値を突っ込むのが間違いだと思うので、スパゲティコードを書きたくない人は素直に、配列に入れるのは1種類の型(もしくはintとfloatみたいに1種類の型とみなしても差し支えない範囲の複数の型)だけにしましょうw


(2013/06/06追記)

Ideone上で実行と書きましたが、一応それぞれの言語のバージョンを書いておきます。

言語 Perl PHP Python Ruby
バージョン perl 5.16.2 php 5.4.4 python 2.7.3 ruby-1.9.3