リスト(配列)に対して存在しないインデックを指定した際に発生するのがこの例外。
“IndexError: list index out of range”
Pythonの話ですけど。
一般的には配列の長さをlenで取得してその範囲に収まるようにすれば問題無いのです。
でもそういうやつばかりじゃない時にちょっと書き方が煮詰まったのでとりあえずブログに書いてみる。
たとえばcsvのファイルがあってそれをリスト&辞書型に格納する。
test.txt(名前[必須]、血液型[任意]、年齢[任意])
hoge,B,33 fuga piyo,AB
Python側はこんな感じ
result = [] with open('test.txt', 'r') as f: for line in f: tmp = line.rstrip().split(',') result.append({ 'name': tmp[0], 'blood_type': tmp[1], 'age': tmp[2] }) print result
これを実行してみると
Traceback (most recent call last): File "hoge.py", line 7, in'blood_type': tmp[1], IndexError: list index out of range
test.txtの2行目に名前しか入ってないのでIndexErrorが発生。
test.txt作る時にカンマの数合わせて入れろと思うことも無いんだけどそうじゃない時もあるってことで進める。
とりあえずIndexErrorが発生しない様に書き換えたのが以下のコード。
三項演算子使って配列の長さ判断した形。
result = [] with open('hoge.txt', 'r') as f: for line in f: tmp = line.rstrip().split(',') result.append({ 'name': tmp[0], 'blood_type': tmp[1] if len(tmp) > 1 else '', 'age': tmp[2] if len(tmp) > 2 else '' }) print result
結果は欲しい形でとれた。
[{'age': '33', 'name': 'hoge', 'blood_type': 'B'}, {'age': '', 'name': 'fuga', 'blood_type': ''}, {'age': '', 'name': 'piyo', 'blood_type': 'AB'}]
もう少し考えて下の形にしてみたもののあまり変わらない。
コードは小さくなったけどわかりやすくなったのかは疑問。
result = [] with open('hoge.txt', 'r') as f: for line in f: tmp = line.rstrip().split(',') result.append({ 'name': tmp[0], 'blood_type': tmp[1] if tmp[1:] else '', 'age': tmp[2] if tmp[2:] else '' }) print result
splitの後にtmpに[”, ”, ”]を追加してしまえば辞書型に変換するときに三項演算子使わなくてもよくなるのですがそれもいまいちかなと。
PHPだとissetがあるしrubyだとnilが返されるのでもうちょっと楽なんですけどね。
stackoverflow先生も漁って見たけどよい解決見当たらない。
他の人がこういった場合にどう書いているのか興味あるところです。ぜひコメントで教えて下さい。
zipを利用するのはどうでしょうか?
fields = [‘name’, ‘blood_type’, ‘age’]
result = []
with open(‘hoge.txt’, ‘r’) as f:
for line in f:
tmp = line.rstrip().split(‘,’)
result.append({name:value for name, value in zip(fields, tmp)})
print result
すばらしい!
zip関数知りませんでした。
これですっきり書けます。
shirebitoさんコメントありがとうございました。