Pythonのmapについて自分なりのまとめ

Python

mapを知りたい

mapを余り使った事が無い中、使う事になったので、一体Pythonにおけるmapとは何なのか簡単にまとめてみる。

チュートリアルを読む

チュートリアルを読むとこんな感じ。

map(functioniterable)

Return an iterator that applies function to every item of iterable, yielding the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see itertools.starmap().

日本語訳を参考にしながら。

function を、結果を返しながら iterable の全ての要素に適用するイテレータを返します。追加の iterable 引数が渡されたなら、 function はその数だけの引数を取らなければならず、全てのイテラブルから並行して取られた要素に適用されます。複数のイテラブルが与えられたら、このイテレータはその中の最短のイテラブルが尽きた時点で止まります。関数の入力がすでに引数タプルに配置されている場合は、 itertools.starmap() を参照してください。

ふんふん、と書いている事を読んでも今一イメージ出来ないのは初心者の弱み。色々試してみよう。
今回知りたいのはmapなので、斜体の部分、itertools.starmap()については未検証です。

最初の一文

Return an iterator that applies function to every item of iterable, yielding the results.

を自分なりに

イテレータ(繰り返しで生み出される数値)を返します、その際にfunctionで設定した計算を適用した上で、適用した算出結果を結果として出力します。

と理解しました。

mapの例

map使用前

>>> numbers = [0, 1, 2, 3, 4]
>>> 
>>> added = []
>>> for i in numbers:
...         added.append(i  + 36)
... 
>>> added
[36, 37, 38, 39, 40]

numbersの構成要素をfor loopで1つずつ獲得して(イテレータ)、それに36をプラスした数字をリストaddedに出力しているコードです。

map使用後

これをmapを使用すると

>>> numbers = [0, 1, 2, 3, 4]
>>> 
>>> def incrs(i):
...     return i + 36
... 
>>> list(map(incrs, numbers))
[36, 37, 38, 39, 40]

となります。

2つの違いは?

この2つはやっている事は余り変わらず、書く面倒さもさほど変わらない気がする。Python本によると、少しmapの方が早いそうで。

速さの検証-普通のfor loop

試してみよう。

timeモジュールをimportした後、頭と最後にtimeの関数を付けて差し引く事で実行時間が図れます。
差異を出す為に、numbersを1万まで増やした上で。

まずは普通のfor loop

>>> t1 = time.time()
>>> 
>>> numbers = [i for i in range(10000)]
>>> 
>>> added = []
>>> for i in numbers:
...     added.append(i  + 36)
... 
>>> print(added)
[36 - 10035]
>>> t2 = time.time()
>>> print(t2 - t1)
0.010183095932006836

速さの検証-map使用

mapを使用した方です。

>> t1 = time.time()
>>> 
>>> numbers = [i for i in range(10000)]
>>> 
>>> def incrs(i):
...     return i + 36
... 
>>> print(list(map(incrs, numbers)))
[36 - 10035]
>>> t2 = time.time()
>>> print(t2 - t1)
0.008019208908081055

確かにfor loopは0.01…ですが、mapの方は0.008…と2割ほど早い!
これはタイミングにもよってきそうですが、概ねmapの方が早めでした。

mapの本当に素敵な所

揃っているデータのみ計算→融通効かせてくれます

ですが、mapが一般のfor loop等と異なるのは説明の内この部分でしょう。

If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted.

追加の iterable な引数が渡された場合、 functionは渡されただけのiterable引数を取ります。その際、渡されたiterable引数の要素に対して並行してfunctionで設定された計算を適用する訳です。
複数のiterable引数が与えられた場合、一番短いiterable引数の要素が尽きた時点で止まります。

と自分なりに理解しました。理解の悪い自分への覚え書きなので超くどい文章になってしまいます。
オフィシャルサイトを翻訳して下さっている方には尊敬の念しか有りません。

どういうことか。
iterableな引数を与えられたらその数だけ平行してfunctionに基づいて計算し、一番要素が少ない引数が終われば計算終了します。

例えば冪乗を算出するpow関数を使った場合

# 1つめ
>>> list(map(pow, [5, 6, 7, 8], [1, 2, 3]))
[5, 36, 343]

# 2つめ
>>> list(map(pow, [5, 6, 7, 8], [1, 2, 3, 4]))
[5, 36, 343, 4096]

となります。

pow関数は引数が2つの場合一つ目の数字を二つ目の数乗する組込関数です。

1つめは5の1乗、6の2乗、7の3乗まで計算した所で2つめのiterable引数[1, 2, 3]が尽きたので終了、2つめは4つずつなので8の4乗まで出力しました。

同じ事をfor loopではどう書くかな?と考えると、listのインデックスで数字を引っ張って、同じインデックス同士で計算する形になるでしょうか。こんなにシンプルには行かなそうです。

書いている内に使い方が分かってきました。
上手く使えば良さそうな関数です。
皆様の情報共有感謝。

コメント

タイトルとURLをコピーしました