ちゅ〜とりある (@.@) 組み込み関数 map

Python.use(better, for=C#) 記事一覧
組み込み関数 map

《著》後藤いるか・森こねこ《監修》小泉ひよ子とタマゴ倶楽部
第0版♪1988/03/30 ● 第1版♪2000/05/23

組み込み関数:map

まず、組み込み関数 map のヘルプ情報を確認します。

>>> help(map)
Help on built-in function map in module __builtin__:

map(...)
    map(function, sequence[, sequence, ...]) -> list
    
    Return a list of the results of applying the function to the items of
    the argument sequence(s).  If more than one sequence is given, the
    function is called with an argument list consisting of the corresponding
    item of each sequence, substituting None for missing values when not all
    sequences have the same length.  If the function is None, return a list of
    the items of the sequence (or a list of tuples if more than one sequence).

組み込み関数 map を適用すると、つねに list が得られます。


《Note》 組み込み関数 map は、すでに Python 1.5 では導入されています。collect:/Smalltalk のような汎用性はありませんが、軽微な問題解決を図りたいときには重宝します。また、OCL にも、同様の collect 操作が規定されています。□

例題を使って、その動作を確認してみましょう。

事例:map〈第3版〉

>>> map(ord, "ABC")
[65, 66, 67]
>>> map(ord, list("ABC"))
[65, 66, 67]
>>> map(ord, tuple("ABC"))
[65, 66, 67]
>>> map(ord, dict((e,ord(e)) for e in "ABC"))
[65, 67, 66]
>>> map(ord, set("ABC"))
[65, 67, 66]

組み込み関数 ord を、str/list/tuple/dict/set に適用すると、文字列の各要素(長さ1の文字列)の ASCII コード値を列挙したリストが得られます。

>>> dict(map(lambda e: (e,ord(e)), "ABC"))
{'A': 65, 'C': 67, 'B': 66}
>>> dict((e,ord(e)) for e in "ABC")
{'A': 65, 'C': 67, 'B': 66}

組み込み関数 map と同等のことは、ジェネレーターでも実現できます。

>>> map(hex, map(ord, (e for e in "ABC")))
['0x41', '0x42', '0x43']
>>> map(hex, (ord(e) for e in "ABC"))
['0x41', '0x42', '0x43']
>>> map(None, (hex(ord(e)) for e in "ABC"))
['0x41', '0x42', '0x43']

組み込み関数 map を多重に適用することもできます。また、第1引数に None を指定すると、第2引数に指定したシーケンスの各要素を列挙したリストが得られます。

>>> (ord(e) for e in "ABC")

>>> [ord(e) for e in "ABC"]
[65, 66, 67]
>>> map(None, (ord(e) for e in "ABC"))
[65, 66, 67]

ジェネレーターでは、各要素を生成するのは、実行時まで遅延されます。リストの内包は、組み込み関数 map の第1引数に None を指定したものと見なせます。

事例:Collection.collect

OCL/Collection で規定された collect 操作に準拠した機能を実現します。

class OCL_Sequence:
    def __init__(self, items):
        self.items = items
    def collect(self, f):
        return reduce(
            lambda acc, e: acc+[e],
            (apply(f, (e,)) for e in self.items),
            [])
>>> OCL_Sequence("ABC").collect(lambda e: ord(e))
[65, 66, 67]
>>> OCL_Sequence("ABC").collect(lambda e: hex(ord(e)))
['0x41', '0x42', '0x43']
>>> OCL_Sequence(range(1, 6)).collect(lambda e: e**2)
[1, 4, 9, 16, 25]

OCL_Sequence をラッパーと見なすと、Python に組み込みのシーケンスに対するメソッドとして、任意の条件処理を記述できます。Smalltalk/collect: のような汎用性はありませんが、軽微な問題解決を図りたいときには重宝します。


《Note》OCL では、任意のコレクションに対する collect 操作

collection->collect(x: T | x.property) 

と等価な表現として、

collection->iterate(x: T; acc: T2 = Bag{} | 
  acc->including(x.property)) 

iterate 操作を利用した実現方法を規定しています。また、collect だけでなく、 reject/select/forAll/exists なども、iterate 操作を枢軸として、実現できることが示されています。これは、任意のコレクションの傘下では、iterate 操作を実現するだけで、他の操作を再定義する必要がないことを意味します。どの操作を枢軸とするかは、任意です。たとえば、Smalltalk では、do: を枢軸に据えて、他のメソッド(collect:/select:/reject:/detect:/inject:into: など)の動作を規定しています。そのため、Collection の傘下では、do: を実現するだけで(その操作を最適化したいときなどを除いて)他のメソッドを再定義する必要はありません。□

Last updated♪09/03/08