配列を制するものはプログラミングを制する
たいていのプログラムではデータ構造として何かしらの配列(または連想配列)が現れて、そして「その全要素に対して何かしらの処理をする」、「配列の全要素を使って、1つの値を算出する」、「配列の中から適切な要素を抽出する」というような処理も頻繁に現れます。言語によっては、これらの処理をきれいに書けるような処理が最初から用意されています。
基本操作 - map
、reduce
、select
配列全体にかけるような基本的な操作として、map
、reduce
、select
などがあります。
map
map
は、ある配列に対して、その全要素に同じ演算を行なってその結果を返すような処理です。
#before
[a[0], a[1], a[2], a[3], a[4], a[5]]
# f() をmapする
[f(a[0]),f(a[1]),f(a[2]),f(a[3]),f(a[4]),f(a[5])]
適用する演算を取り替えることで、「全要素を文字列に変換する」とか「全要素を0.1の位で四捨五入する」とか、多様な目的に使えます。
reduce
map
は、ある配列に対して、同じ演算を繰り返し適用して、1つの値を抽出する処理です。
#before
[a[0], a[1], a[2], a[3], a[4], a[5]], initial_value
# f() でreduceする
value = f(initial_value, a[0])
# 初期値を指定せず、a[0]とa[1]でスタートすることもたいてい可能
value = f(value, a[1])
value = f(value, a[2])
value = f(value, a[3])
value = f(value, a[4])
value = f(value, a[5])
これだけではピンとこないと思いますので、具体的なf()
の例と、最終結果を挙げてみます。
-
f()
で両者の加算→配列全体の総和 -
f()
で両者の乗算→配列全体の総乗 -
f()
で文字列連結→配列全体を1つの文字列につないだもの -
f()
で大きい方→配列全体の最大値
このように、適切な関数を選ぶことで多様な処理に使えます。なお、初期値として空の配列を与えて、f()
として「2つ目の引数の値に適当な演算を行なって、1つ目の配列に追加する」ということを行うと、map
としても使えます。
select
これは配列と、「要素を取ってtrue/falseを返す関数」を使って、配列の中から条件に合うものだけ抽出するという機能です。関数の符号を逆転させれば、条件に合わないものだけ抽出も容易にできます。
PHP
PHPでは、array_map
やarray_reduce
、array_filter
という関数があって、それぞれmap
やreduce
、select
に使えます。なお、関数リテラルやそれを変数に入れたもの以外を関数として使う場合、名前の文字列、あるいはarray(オブジェクト,'メソッド名')
のような配列を渡すことになります(callable)。
// $aの中身をすべてintにする
$b = array_map('intval', $a);
// $c の合計値を計算する(array_sumもあるけど)
$d = array_reduce($a, function($val, $curr){
return $val + $curr;
});
// $eから文字列だけを抽出する
$f = array_filter($e, 'is_string');
なお、array_map
だけ関数が先に来ていますが、これは複数の配列をとれるという事情が故で、ミスではありません。また、array_filter
で関数を省略すると、「truthyなものだけ取り出す」という意味になります。
Ruby
Rubyでは、配列だけでなく、each
メソッドを持つ多くのクラスにEnumerable
がmix-inされていて、こちらでmap
、reduce
、select
などが定義されています。
# a の中身をすべて整数にする
b = a.map{|item| item.to_i}
# 上の行と全く同じ
b = a.map(&:to_i)
# cの合計値を計算する
d = c.reduce{| total, val | total + val }
# 上の行と全く同じ
d = c.reduce(&:+)
# eから 文字列だけを抽出する
f = e.select{|v| v.is_a?(String)}
なお、引数で&:メソッド
とすると、{|オブジェクト, *残りの引数| オブジェクト.メソッド *残りの引数}
というようなブロックを渡したものとして処理されます(Symbol#to_proc)。また、map
にはcollect
、reduce
にはinject
という別名があります。
CoffeeScript
CoffeeScriptには、「配列内包」という、map
とselect
を一気に行えるような機能があります。記法としては、
coffeescript
( 式 for 変数 in 配列 when 条件 )
というような形になっています(なお、条件が不要な場合、when 条件は省略できますが、逆に値を加工しなくていい場合はfor
の前後に同じ変数を書く必要があります)。たとえば、「配列から奇数だけ抽出して、値を3倍して1を足す」ということをする場合、arr2 = (3 * i + 1 for i in arr when i % 2 == 1)
とシンプルに書けますが、これをJavaScriptにコンパイルすると
arr2 = (function() {
var j, len, results;
results = [];
for (j = 0, len = arr.length; j < len; j++) {
i = arr[j];
if (i % 2 === 1) {
results.push(3 * i + 1);
}
}
return results;
})();
という膨大な量のコードになります。なお、ES5にもArray.prototype.filter()
やArray.prototype.map()
がありますが、実は(これらの関数には仕様上in
での存在チェックが入ることもあって)ループを書いたほうが速度が出るので、特にCoffeeScriptからこれらの関数を使う必要はあまりないでしょう。Array.prototype.reduce()
は使うかもしれませんが(IE8を切ってもいいなら)。
Author And Source
この問題について(配列を制するものはプログラミングを制する), 我々は、より多くの情報をここで見つけました https://qiita.com/jkr_2255/items/1b4329e5bc31f6ee606b著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .