濾過演算とは
UNIX 文化では, パイプやリダイレクトで連結することで組み合わせ可能な, 入力を加工して出力する (比較的) 小さな機能のプログラムのことを総じて「フィルタ(濾過器)」と呼びます.
が,
ここで, 題材にする演算は上記の意味ではありません.
引数を一つとり, 真偽値を返す演算「述語 (predicate)」と, 「データ列」を与えると, データ列のうち「述語」が真を返す要素のみ取り出したデータ列を返すような演算は, 多くのプログラミング言語において, 組み込みで, または, 基本ライブラリで提供される大変汎用的な演算です.
言語によって filter
, select
などの名前で提供されています. 本記事では, 便宜的に「濾過演算」と呼びますが, この日本語名称が一般的という訳でもありません.
多くの繰り返し処理は濾過に抽象化されます.
a = <新しい空のデータ列>;
for (i = 0; i < <データ列>.長さ; i++) {
if (<述語>(<データ列>[i])) {
a.append(<データ列>[i]);
}
}
return a;
のような形の演算は
<濾過> <述語> <データ列>
のように抽象化できます.
また, 濾過として抽象化すると, データ列全体を読み込んで処理する必要がなく, 非常に大きなデータ列に対してシーケンシャルに処理が可能であるという利点もあります. (実装によりますが, あくまでこの抽象化において原理的には.)
以下
- Ruby の
select
- JavaScript の
filter
- Clojure の
filter
で例示します.
以下の環境で試験しました.
% irb --version
irb 0.9.6(09/06/30)
% node --version
v0.10.26
% java -jar clojure-1.7.0.jar
Clojure 1.7.0
user=>
数値の濾過
数値列中の偶数のみ抽出します.
Ruby
irb(main):001:0> [3, 1, 4, 1, 5, 9, 2, 6].select{|i| i%2 == 0}
=> [4, 2, 6]
JavaScript
> [3, 1, 4, 1, 5, 9, 2, 6].filter(function(i){return i%2 == 0})
[ 4, 2, 6 ]
Clojure
user=> (filter even? [3 1 4 1 5 9 2 6])
(4 2 6)
文字列の濾過
文字列の列から長さが 3 以上のものを抽出します.
Ruby
irb(main):002:0> ["May", "I", "have", "a", "large", "container", "of", "coffee"].select{|i| 3 <= i.length}
=> ["May", "have", "large", "container", "coffee"]
JavaScript
> ["May", "I", "have", "a", "large", "container", "of", "coffee"].filter(function(i){return 3 <= i.length})
[ 'May',
'have',
'large',
'container',
'coffee' ]
Clojure
user=> (filter #(<= 3 (count %)) ["May" "I" "have" "a" "large" "container" "of" "coffee"])
("May" "have" "large" "container" "coffee")
シェルで
前置きが長くなりました. 濾過演算を実装する Bourne Shell スクリプトは以下のようになります.
#!/bin/sh
f=$1
while read line
do
set "$line"
if `eval $f`
then
echo $line
fi
done
- 述語は, 第一引数に「引数を一つとり真偽値を返すプログラム」を与えます.
- データ列は, 改行区切りで標準入力から与えられるものとします.
真偽値を返すプログラムは「Bourne Shell の if
にとって」の真偽ですので, 終了ステータス 0 で終了が真, 0 以外は偽とします. if
に対して頻繁に行うように, test
コマンド(
MAN page of TEST) のハードリンクである [
を使うことで, 多くの場合は目的に適うでしょう.
上記を filter
として PATH 環境変数に含まれるディレクトリに保存 (または保存したディレクトリを PATH に追加) し, 実行パーミッションを与えてある (chmod +x filter
してある) ものとして, 以下使い方を例示します.
$/bin/sh --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
Copyright (C) 2007 Free Software Foundation, Inc.
で試験しました.
数値の濾過
数値列中の偶数のみ抽出します.
$ echo "3 1 4 1 5 9 2 6" | tr ' ' '\n' | filter '[ `expr $1 % 2` -eq 0 ]'
4
2
6
文字列の濾過
文字列の列から長さが 3 以上のものを抽出します.
$ echo "May I have a large container of coffee" | tr ' ' '\n' | filter '[ 3 -le ${#1} ]'
May
have
large
container
coffee
お読みいただきありがとうございました.