Pythonのリストを要素だけじゃなくてインデックス付きで取得したい
辞書やJSONもインデックス付きで取得できたら良いんだけど……
enumerate関数ってなに? 基本的な使い方を知りたい!
リストや辞書の要素を取得するとき、繰り返し処理のfor文を使うことが多いと思います。でも、「要素だけじゃなくてインデックスも取得したい」なんてケースも多くありますよね。
そんなとき、range関数を使っていたりしませんか? それなら、今日からはenumerate関数を使ってみましょう!
「enumerate」を使うと、リストの要素とインデックスのセットを簡単に取得できます。この記事では、リストや辞書、JSONの全要素をインデックス付きで処理するコードを紹介します。
こんな方はぜひ最後までお付き合いください!
- リスト・辞書の要素をインデックス付きで取得したい方
- JSONの要素もインデックス付きで取得したい方
なお、この記事のサンプルコードはPython 3.7.3で実装および動作確認を致しました。
本記事を読む前に、Pythonがどんなプログラミング言語なのかをおさらいしておきたい人は次の記事を参考にしてください。
→ Pythonとは?特徴やできること、活用例をわかりやすく簡単に解説
なお、その他のPythonの記事についてはこちらにまとめています。
Pythonのenumerate関数とは
以下の「sample.py」を見てください。
items = ['要素1', '要素2', '要素3'] for item in items: print(item)
これを以下のコマンドで実行すると、
$ python sample.py
実行結果:
要素1 要素2 要素3
普通に要素が取り出せましたね。これでじゅうぶんな事も多くありますが、一方で要素だけではなく「これが何番目の要素か」という情報(=インデックス)が欲しくなるケースもよくあります。
そんなときに使えるのが、enumerate関数です。
enumerate関数は、繰り返し処理の中でリストや辞書の要素をインデックス付きで取得することができます。for文と組み合わせれば、全要素とそれぞれのインデックスの取得が可能です。
0 要素1 1 要素2 2 要素3
一例として、実際のコードを見てみましょう。enumerate関数は2行目で使われています。
enumerate関数の書き方:
fruits = ['apple', 'orange', 'banana'] for (i,j) in enumerate(fruits): #enumerate(リスト)という形 print(i,j)
実行結果:
0 apple 1 orange 2 banana
どうでしょう? for文とほとんど変わらないコード量で、0,1,2と番号が付けられていますね。
実行結果からiが0から1ずつ増えているのが読み取れます。このiをインデックスといいます。
以下の記事ではenumerateの基本的な使い方を取り上げていますので、あわせてご覧いただければと思います。
enumerate関数の使い方【基本編】
まずはenumerateの基本的な使い方を解説します。
基本構文
for 変数1,変数2 in enumerate(リスト等の変数): #for文の中身
このように記述すると、変数1にインデックスの値が代入されて、変数2にリストの要素が代入されていきます。
また、それぞれの変数名に縛りは特にありません。
インデックスの開始番号を指定したい場合
enumerate関数では、start引数を指定することで、インデックスの開始番号を自由に設定する事ができます。
以下のコードでは、試しに1を指定してみました。
fruits = ['apple', 'orange', 'banana'] for (i,j) in enumerate(fruits, start=1): print(i,j)
実行結果:
1 apple 2 orange 3 banana
実行結果を見てみると、インデックスが0からではなく、1から始まっていますね。
enumerate関数の使い方【応用編】
次は、応用的な使い方です。
辞書の全要素をインデックス付きで取得する方法
ここでは、辞書をenumerateで要素を取り出します。リストと同じようにコードを書いてみましょう。
X3 = {"taro": "pw1", "hanako": "pw2", "itiro": "pw3", "yui": "pw4"} for (k,v) in enumerate(X3): print(k,v)
実行結果:
0 taro 1 hanako 2 itiro 3 yui
確かにインデックスは付いていますが、辞書のキーのみが出力されていて”pw1″などが取れていません。これでは意味がありませんね。
そこで辞書に「辞書.items()」とすると、要素をリストで出力できるのはご存知でしょうか。辞書の要素をリストにできれば、enumerateと組み合わせて使えますね。
X3 = {"taro": "pw1", "hanako": "pw2", "itiro": "pw3", "yui": "pw4"} for (k,v) in enumerate(X3.items()): print(k,v)
実行結果:
0 ('taro', 'pw1') 1 ('hanako', 'pw2') 2 ('itiro', 'pw3') 3 ('yui', 'pw4')
これで全要素をインデックス付きで取得できました。なお、辞書の取り扱いについては、以下の記事でも紹介していますので、あわせてご覧ください。
JSONの全要素をインデックス付きで取得する方法
最後にJSONの全要素をインデックス付きで取得する方法です。
読み込むJSONファイルは以下のとおりです。ファイル名は、test.jsonとしました。
{ "profile1": { "first": "Tarou", "last": "Tanaka" }, "profile2": { "first": "Hanako", "last": "Yamada" } }
JSONは、json.load()で辞書として読み込めますので、辞書をリストにしてenumerateと組み合わせる方法を使えば良さそうですよね。
しかし、JSONは階層が深くなることがあるので注意が必要です。そこで以下の点を工夫します。
- enumerate_dict関数を定義して再帰的に呼び出す
- インデックスは階層構造を反映した形にするため、リストのappend(), pop()を使って格納する
import json def enumerate_dict(dic, idx): for (i,v) in enumerate(dic.items()): idx.append(i) if (isinstance(v[1],dict)): #次の階層がある場合 print(idx, v[0]) enumerate_dict(v[1],idx) else: #次の階層が無い場合 print(idx, v) idx.pop() idx = [] with open('test.json', 'r') as f: json_dict = json.load(f) enumerate_dict(json_dict, idx)
実行結果:
[0] profile1 [0, 0] ('first', 'Tarou') [0, 1] ('last', 'Tanaka') [1] profile2 [1, 0] ('first', 'Hanako') [1, 1] ('last', 'Yamada')
これでJsonの階層構造を反映した形で取得できました。
インデックスだけが取得したい場合の書き方
これは書き方のお話ですが、インデックスだけ必要で、要素は使わないという場合はその旨を明示的に書いておく方が可読性が高まります。
具体的にfor文を
for インデックス, _(アンダースコア) in リスト:
と記述する事で、要素の部分は使わないという事が示せます。
fruits = ['apple', 'orange', 'banana'] for i,_ in enumerate(fruits, start=1): #要素の箇所は"_"とする print(i)
実行結果:
1 2 3
“i, v”として、vを使わないという形式でも処理に違いはありませんが、「ここでは使わないよ」という意思表示があると、後々メンテナンスしやすくなることもありますので覚えておきましょう。
まとめ
今回の記事では、enumerate関数を使ってリストや辞書、JSONの要素をインデックス付きで取得する方法を説明しました。
JSONのインデックスについては通し番号のほうが良いという考え方もあると思いますが、複雑なJSONであっても対応できますので、参考までに知っておいていただけると嬉しいです!
for文+カウンタ用の変数を使うよりも、enumerateを使って記述した方がスマートなコードになります。是非ここで使い方を覚えて、活用していってください!