Python.use(better)《余録》組み込み関数 filter
‖記事一覧‖ Python.use(better)《Python3.1》
《余録》組み込み関数 filter
さまざまな事例
簡単な事例を使って、組み込み関数 filter の理解を深めます。
《Note》Smalltalk-80 セミナー用に作成した課題を、Python で再構成しました。この課題では「コレクションを扱う基本的なプロトコル(collect:/select:/reject:/detect:/inject:into:)を利用する」という制約を課してあるので、問題解決のための「最適解」を示すものではありません。
組み込み関数 filter
$ python3.1 Python 3.1 (r31:73578, Jun 27 2009, 21:49:46) [GCC 4.0.1 (Apple Inc. build 5493)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> >>> print(filter.__doc__) filter(function or None, iterable) --> filter object Return an iterator yielding those items of iterable for which function(item) is true. If function is None, return the items that are true. >>>
関数 function を、iterables の各要素に適用した結果を列挙する、イテレーターを生成します。
- function に None を指定すると、iterables の各要素で true と評価されたものを列挙する、イテレーターを生成します。
■ 事例:リストの内包
>>> [e for e in "ABC" if ord(e)%2] ['A', 'C']
文字列 "ABC" の各要素 e(長さ1の文字列)の中から、if に続く条件式を満たす要素を列挙した、リストが得られます。リストの内包と同等の結果は、次のように、組み込み関数 filter でも得られます。
>>> filter(lambda e:ord(e)%2, "ABC")
<filter object at 0xeed10>
>>> list(_)
['A', 'C']
文字列 "ABC" の各要素 e の中から、if に続く条件式を満たす要素を列挙する、イテレーターが得られます。そこで、これをもとにリスト list を生成します。
■ 事例:第1引数に None を指定する
>>> [e for e in range(6) if e%3] [1, 2, 4, 5]
数列 range(6) の各要素 e(0 から 5 までの整数)の中から、if に続く条件式を満たす要素を列挙した、リストが得られます。すると、次のように、
>>> filter(None, [e%3 for e in range(6)])>>> list(_) [1, 2, 1, 2]
第1引数に None を指定すると、数列 range(6) の各要素 e(0 から 5 までの整数)の中から、式 e%3 の値が True になる(3 の倍数でない)要素を列挙した、リストが得られます。
課題:九九の表〔filter 版〕
組み込み関数 filter を用いて、掛算の九九の表を作成します。*1。
def multiplicationTable():
for n in range(2, 10):
for e in filter(lambda e: not e%n, range(n, n*10)):
print("%2d"%e, end=" ")
print()
>>> multiplicationTable()
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
filter を使って、任意の数 n の倍数を残してふるいに掛けます。
事例:エラトステネスのふるい(素数)
任意の数n以下の素数が得られます *2。filter(フィルター:ふるい)という言葉から、すぐに思い浮かぶのが「エラトステネスのふるい」です。
def prime(n): return reduce( lambda acc, n: filter(lambda e: e==n or e%n, acc), range(2, int(sqrt(n))+1), range(2, n+1))
>>> prime(100)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
reduce を使って累積される情報は、反復処理ごとにその要素が減ってもかまいません。filter を使って n の倍数をふるいに掛けると、最後に素数だけが残ります。
課題:OCL/Sequence.select
《Note》OCL では、次のような操作が規定されています。
select(expression: OclExpression): Sequence(T) source->select(iterator | body) = source->iterate(iterator; result: Sequence(T) = Sequence{} | if body then result->including(iterator) else result endif)
これを見ると、iterate 操作に関わる部分を除くすべてが、Sequence で規定されたプロトコル(Template パターン)に従うことが分かります。そのため、Sequence の傘下では、iterate 操作を実現するだけで(その操作を最適化したいときなどを除いて)select 操作を再定義する必要はありません。□
OCL/Sequence で規定された select 操作に準拠した機能を実現します。
class OCL_Sequence(OCL_Collection):
def __init__(self, items):
self.items = items
def select(self, f):
return [e for e in self.items if f(e)]
>>> OCL_Sequence("ABC").select(lambda e: ord(e)%2) ['A', 'C'] >>> OCL_Sequence(range(10)).select(lambda e: e>5) [6, 7, 8, 9] >>> OCL_Sequence(range(10)).select(lambda e: e%2) [1, 3, 5, 7, 9]
OCL_Sequence をラッパーと見なすと、Python に組み込みのシーケンスに対するメソッドとして、任意の条件処理を記述できます。Smalltalk/select: のような汎用性はありませんが、軽微な問題解決を図りたいときには重宝します。
》こちらに移動中です《
↑TOP
関連記事
- Python への扉
- INDEX《Python》filter
- 2002-01-26 Python.use(better)《余録》comprehension: list