質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

3回答

2916閲覧

python3のmap関数について

grilled_python

総合スコア237

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/03/14 08:06

ラムダ式を勉強しているとmap関数が出てきました。
最後にリスト型にしないと、何故プリントできないのが理解できません。よろしくお願いします。

https://www.sejuku.net/blog/24759

こちらによると、map関数とは「シーケンスの各要素に同じ処理をかける方法」とのこと

例題
original_list = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
mapped_list = map(lambda x: x**2, original_list)

print(list(mapped_list))

結果
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

一行づつの私の理解
original_list = list(range(10))
original_listに0~9までのリストが格納される

mapped_list = map(lambda x: x**2, original_list)
xを2倍する関数(ラムダ式)をマップ関数でoriginal_listの要素に処理をしてmapped_listに格納

print(list(mapped_list))
mapped_listをリスト型にしてプリント

疑問
list()を除いて
print(mapped_list)とすると
<map object at 0x000001EC31370F28>と表示されます。

map objectとはなにか?
そのままprint(mapped_list)だとなぜ駄目なのか?

調べたらmap型って出てきたんですが、map型ってあるんですか?
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

mapがしていることの確認

まず、リストを返す『map的な何か』を作ってみましょう。

Python

1def my_map(func, it): 2 return [func(e) for e in it]

そして、実際のmapと動作を比較してみます。

Python

1>>> for e in my_map(lambda x: x*2, [1, 2, 3]): 2... print(e) 3... 42 54 66 7>>> for e in map(lambda x: x*2, [1, 2, 3]): 8... print(e) 9... 102 114 126

ここまでは全く同じ動作をしているように見えますね。

なぜmapを用いるのか?

さて、値を算出するのに物凄く時間がかかる関数があるとします。

Python

1def some_func(e): 2 print('Waste long long long time') 3 return 2*e

これを用いて、またmy_mapとmapを比較してみましょう。

Python

1>>> for e in my_map(some_func, [1, 2, 3]): 2... print(e) 3... 4Waste long long long time 5Waste long long long time 6Waste long long long time 72 84 96 10>>> for e in map(some_func, [1, 2, 3]): 11... print(e) 12... 13Waste long long long time 142 15Waste long long long time 164 17Waste long long long time 186

結果が変わりましたね。ここがミソです。
mapは、実際に必要になるまで値を算出しません。これを一般に遅延評価と言います。

なぜ遅延評価が便利か?

先の例で、特にsome_funcが毎度ms秒時間を消費したとします。

  • my_mapの場合、全て計算してからリストを返します。

ループ自体は高速ですが、ループに入るまでに少なくともリスト長 * ms秒を要します。

  • mapの場合、ループしながら毎度値を計算します。

一周につきms秒待ちますが、ループに突入するまでの待ち時間はほとんどありません。

基本的に待ち時間は分散させた方がストレスが無いですし、
途中でループを脱出する際にも無駄な計算をしなくて済みます。

追記:メモリの浪費を防げるという大きなメリットを抜かしてしまった...

一問一答

map objectとはなにか?

毎度必要な値を計算してくれる、ジェネレータイテレータの一種です。
Qiita - Pythonのイテレータとジェネレータ

そのままprint(mapped_list)だとなぜ駄目なのか?

mapを実行しただけでは計算は行われないからです。
なお、すぐにリストに直すのであれば、mapを使うメリットはあまりないです。

調べたらmap型って出てきたんですが、map型ってあるんですか?

Pythonでは文化上、関数とクラスをあまり厳密に区別しません。
関数だと思ったらクラスだった、と言うことはしばしばあります。

投稿2018/03/14 08:27

編集2018/03/14 08:32
LouiS0616

総合スコア35658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

grilled_python

2018/03/14 08:57 編集

大変丁寧に、わかりやすくありがとうございます。すっきりしました。 特にmapとmap的ななにかを比較して頂いた所でmap関数とは何かが理解できたと思います。
guest

0

map objectはジェネレーターです。
ジェネレーターはイテレーターの一部なので、イテレーターと読み替えて頂いても大丈夫です。
なので質問はジェネレーターとは何か?に帰着されると思います。

ジェネレーターは何らかの値を生成する関数です。
map objectそのものをprintしても値は生成されませんが、forループの中や、リスト関数に入れることによって値が生成されて表示することができるようになります。

リストとの違いですが変換した時にメモリに展開されるので、巨大な値を生成するジェネレータだった場合はその分メモリを消費します。
無限に値を生成するジェネレータだった場合は処理が止まりません。
ジェネレータの場合はforループを処理する際、内部的にはnext()関数を呼ばれた時だけ値を一つずつ生成するので、メモリを効率的に使うことができます。

同じような働きをする関数としては、filter()やitertools以下の色んなメソッド(itertools.countなど)があります。

投稿2018/03/14 08:29

kawarayu

総合スコア55

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

grilled_python

2018/03/14 08:50

ご回答ありがとうございました。
guest

0

Louis0616さんの説明のとおりですが、一点だけ補足注意点を。
mapはイテレータでもあるので、一度評価(実行)すると、末尾に位置します。
すなわち、以下のコードにおいて2回目以降list(m)と実行しても(末尾から動かないので)結果は空になります。

ちなみにイテレータの位置を先頭に戻す手段は一般的には用意されていません。
イテレータ (iterator)

イテレータは次に進むことしかできませんのでご注意ください; 前の要素を手に入れたり、イテレータをリセットしたり、コピーを作ったりする方法はありません。イテレータがオブジェクトとしてそうした追加機能を 持つことはできますが、プロトコルでは next() メソッドのことしか指定されていません。ですから関数はイテレータの出力を使い尽くして しまうかもしれませんし、同じストリームに何か別のことをする 必要があるなら新しいイテレータを作らなくてはいけません。

参考:Listing a filter object twice will return a blank list?

Python

1import time 2 3def func(n): 4 time.sleep(1) 5 print('func({})'.format(n)) 6 return n ** 2 7 8print('map') 9m = map( func, [1,2,3]) 10print(m) 11time.sleep(1) 12 13print('list1') 14l1 = list(m) # ここで評価(実行)される 15print(l1) # [1,4,9] 16 17print('list2') 18l2 = list(m) 19print(l2) # []! すでにイテレータ末尾に到達しているので。

投稿2018/03/14 08:38

編集2018/03/14 08:43
can110

総合スコア38233

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

grilled_python

2018/03/14 08:49

ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問