LoginSignup
4
2

More than 5 years have passed since last update.

Python で `*.aa.*.bb.*` のようなパスを使って dict から値のリストを取り出す方法

Last updated at Posted at 2018-12-11

概要

*.aa.*.bb.* のようなパスを書いて複雑な dict から値のリストを取り出す方法を紹介します。

準備

下記を定義します。

def extract_all(data, keys_str, values=None):
    if values is None:
        values = []
    if keys_str == '':
        values.append(data)
    else:
        keys_list = keys_str.split('.')
        key = keys_list.pop(0)
        if key == '*':
            if type(data) == dict:
                data = data.values()
            for v in data:
                extract_all(v, '.'.join(keys_list), values)
        elif key in data:
            v = data[key]
            extract_all(v, '.'.join(keys_list), values)
    return values

これだけです。

使い方

# 複雑な dict
data = dict(
    a=dict(aa=[
        dict(bb=[111, 112]),
        dict(bb=[121, 122]),
    ]),
    b=dict(aa=[
        dict(bb=[211, 212]),
        dict(bb=[221, 222]),
    ]),
    c=dict(),
)

print(extract_all(data, '*'))
# 出力:
#  [{'aa': [{'bb': [111, 112]}, {'bb': [121, 122]}]},
#   {'aa': [{'bb': [211, 212]}, {'bb': [221, 222]}]},
#   {}]

print(extract_all(data, '*.aa'))
# 出力:
#   [[{'bb': [111, 112]}, {'bb': [121, 122]}],
#    [{'bb': [211, 212]}, {'bb': [221, 222]}]]

print(extract_all(data, '*.aa.*'))
# 出力:
#   [{'bb': [111, 112]},
#    {'bb': [121, 122]},
#    {'bb': [211, 212]},
#    {'bb': [221, 222]}]

print(extract_all(data, '*.aa.*.bb'))
# 出力:
#   [[111, 112], [121, 122], [211, 212], [221, 222]]

print(extract_all(data, '*.aa.*.bb.*'))
# 出力:
#   [111, 112, 121, 122, 211, 212, 221, 222]
  • 該当のパスが存在しない場合エラーにはらず、単純にリストから除外されます。

まとめ

不安定かつ複雑なデータをあつかう際に上記があれば、個々にエラーハンドリング書く必要なくなるのでソースの可読性をあげられます。

また、 Python で複雑な構造の dict オブジェクトをセレクタ的にアクセスできるようにする という記事で、パスの途中が無い場合にフルパスでエラー出してくれるクラスを紹介してますので、よろしければそちらもご覧ください。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2