読者です 読者をやめる 読者になる 読者になる

歩いたら休め

If the implementation is easy to explain, it may be a good idea.

【Python】Pythonのmap関数とreduce関数でちょっとしたリスト操作を楽にする

SoftwareDesign8月号に関数型プログラミング特集があり、その中に『Pythonで見る関数型言語の本質』という素晴らしい特集があります。

スクリプト言語であればRubyとかRとかのほうが関数型っぽい気がしますが、Pythonはシンプルでとっつきやすく、マルチパラダイムな言語なので関数型の考え方も勉強しやすいのかもしれません。

あと関連する記事としてコレも良かったです。

qiita.com

 ぶっちゃけこれらの記事を読めばOKなのですが、せっかくなのでちょっとしたデータ解析やってみましょう。

map関数でリスト(連想配列)からデータを取り出す

日本全国の郵便番号が取得できる以下のAPIを使って、日本中の"大手町"の名のつく住所を取得したいとします。

RESTful Zip Search API Specification -- ricollab

import urllib.request, json
req = urllib.request.Request('http://zip.ricollab.jp/search?q=大手町&type=json&count=500') 
with urllib.request.urlopen(req) as response:
    response_read = response.read().decode('utf-8')
    jsondata = json.loads(response_read)

このとき、json変数の中身はこんな感じの辞書型(連想配列)になってます。

{'itemsPerPage': 500,
 'query': '大手町',
 'result': [{'address': '北海道函館市大手町',
   'link': 'http://zip.ricollab.jp/0400064',
   'zipcode': '0400064'},
  {'address': '岩手県一関市大手町',
   'link': 'http://zip.ricollab.jp/0210884',
   'zipcode': '0210884'},
  {'address': '岩手県奥州市水沢区大手町',
   'link': 'http://zip.ricollab.jp/0230053',

この中から住所('address')の一覧を取得するには、以下のmap関数を使えば一発です。for文を回すより楽。

list(map(lambda x:x['address'], jsondata['result']))

実行結果は次のように出てきます。

['北海道函館市大手町',
 '岩手県一関市大手町',
 '岩手県奥州市水沢区大手町',
 '宮城県仙台市青葉区大手町',
 '宮城県石巻市大手町',
…

reduce関数でリスト(連想配列)の中のリストを結合する

また、ちょうどいいデータが見つからなかったのですが、こんな感じのデータを扱うことがありました。九州の県の検索結果だと考えてください。

[{'都道府県': '大分県',
    '市区町村': ['大分市', '日田市', '別府市']},
    {'都道府県': '福岡県',
    '市区町村': ['福岡市', '北九州市', '久留米市'],
    {'都道府県': '熊本県',
    '市区町村': ['熊本市', '水俣市']}]

この中から、九州の市区町村のリストを取得したいとします。

これに対して、先ほどと同じようにmap関数を適用してみようと思います。上の連想配列はprefという変数に格納されているとします。

map(lambda x:x['市区町村'], pref)

そうすると、こんな出力結果。

[['大分市', '日田市', '別府市'], ['福岡市', '北九州市', '久留米市'], ['熊本市', '水俣市']]

そこで、reduce関数を使って、中のリストを結合させるコードを書いてみます。Pythonでは+演算子でリストとリストを結合できます。また、Python2系でreduce関数はデフォルトの関数だったようですが、Python3系からfunctoolsというモジュールに搭載されるようになりました。

from functools import reduce
tmp = map(lambda x:x['市区町村'], pref)
citylist = reduce(lambda x,y: x+y, tmp)
print(list(citylist))

この出力結果がコレ。

['大分市', '日田市', '別府市', '福岡市', '北九州市', '久留米市', '熊本市', '水俣市']

他にも関数型っぽい便利な機能はいろいろあります。気になる方は前述の記事を読んでください。

 

ところで、一度LAND OF LISPを読んでからRやPythonの関数型っぽい操作が自然にできるようになった気がします。データ解析をする人は、リスト・配列の操作が多いと思うので、それらの操作が得意な関数型言語を一度触ってみることをおすすめします。

 

Land of Lisp

Land of Lisp