PHPにおける不要な配列の最適化
あるプログラマーに、1から100000000までの整数の合計を見つけるという課題が与えられたとします。
このプログラマーは、この課題に対するエレガントな解決策を次のように書きました。
<?php
echo array_sum(range(1, 100000000));
?>
美しい解決策ですね。一行で済んでいます。しかし、これは機能しません!このコードを実行してみると、メモリを要求しすぎているというエラーが表示されます。
えっと、100000000ってそんなに多くないのでは?それとも多い?計算してみましょう。関数rangeは、100000000個の数値を持つ配列を作成します。PHPが1つの数値に2バイトを割り当てると仮定すると、この配列を保存するには200000000バイト、つまり約200メガバイトのRAMが必要になります。
しかし実際には、PHPでは配列を保存する際のオーバーヘッドが非常に大きいため、はるかに多くのRAMが必要になります。例えば、私の環境でのエラーメッセージは、4294967304バイト(約4ギガバイト)の割り当てを試みていると表示しています。
エラーが発生する理由がわかりましたね。許可されているメモリ制限をはるかに超えてしまっています。
このスクリプトを、実質的にRAMを消費しない別の方法に書き換えるのはそれほど難しくありません。
<?php
$sum = 0;
for ($i = 1; $i <= 100000000; $i++) {
$sum += $i;
}
echo $sum;
?>
さらに良いのは、数学的な解決策を使うことです。
<?php
$n = 1000000;
$sum = $n * ($n + 1) / 2;
echo $sum;
?>
あるプログラマーに、与えられた数の階乗を見つけるという課題が与えられました。 彼は次のように解決しました。
<?php
$n = 100;
echo array_product(range(1, $n));
?>
このコードの何が問題なのか説明してください。より最適なコードに書き直してください。
あるプログラマーに、1から1000000までのすべての整数を書くために必要な桁数を見つけるという課題が与えられました。
彼は次のように解決しました。
<?php
echo strlen(implode('', range(1, 1000000)));
?>
このコードの何が問題なのか説明してください。より最適なコードに書き直してください。
あるプログラマーに、指定された範囲内で7で割り切れる数の個数を見つけるという課題が与えられました。
彼は次のように解決しました。
<?php
$arr = [];
for ($i = 0; $i <= 1000; $i++) {
if ($i % 7 == 0) {
$arr[] = $i;
}
}
echo count($arr);
?>
このコードの何が問題なのか説明してください。より最適なコードに書き直してください。
あるプログラマーに、数の約数の合計を見つけるという課題が与えられました。 彼は次のように解決しました。
<?php
$num = 320;
$divs = [];
for ($i = 0; $i <= $num; $i++) {
if ($num % $i == 0) {
$divs[] = $i;
}
}
echo array_sum($divs);
?>
このコードの何が問題なのか説明してください。より最適なコードに書き直してください。